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_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapprecision;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 rtexture_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmaprectangletexture;
248 rtexture_t *r_shadow_shadowmap2dtexture;
249 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 // lights are reloaded when this changes
255 char r_shadow_mapname[MAX_QPATH];
257 // used only for light filters (cubemaps)
258 rtexturepool_t *r_shadow_filters_texturepool;
260 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"};
261 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"};
262 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
263 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
264 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)"};
265 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"};
266 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
267 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
268 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
269 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
270 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
271 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
273 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
274 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
275 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
276 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)"};
277 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
278 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
279 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
280 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
281 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)"};
282 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"};
283 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
284 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
285 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"};
286 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
287 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
288 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)"};
289 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"};
290 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"};
291 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)"};
292 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
293 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
294 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
295 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
297 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
298 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
299 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
300 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
301 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
302 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
303 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)"};
304 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)"};
305 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
306 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"};
307 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
308 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
309 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
310 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
311 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
312 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
313 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
314 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
315 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
316 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
318 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
319 #define ATTENTABLESIZE 256
320 // 1D gradient, 2D circle and 3D sphere attenuation textures
321 #define ATTEN1DSIZE 32
322 #define ATTEN2DSIZE 64
323 #define ATTEN3DSIZE 32
325 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
326 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
327 static float r_shadow_attentable[ATTENTABLESIZE+1];
329 rtlight_t *r_shadow_compilingrtlight;
330 static memexpandablearray_t r_shadow_worldlightsarray;
331 dlight_t *r_shadow_selectedlight;
332 dlight_t r_shadow_bufferlight;
333 vec3_t r_editlights_cursorlocation;
335 extern int con_vislines;
337 typedef struct cubemapinfo_s
344 #define MAX_CUBEMAPS 256
345 static int numcubemaps;
346 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
348 void R_Shadow_UncompileWorldLights(void);
349 void R_Shadow_ClearWorldLights(void);
350 void R_Shadow_SaveWorldLights(void);
351 void R_Shadow_LoadWorldLights(void);
352 void R_Shadow_LoadLightsFile(void);
353 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
354 void R_Shadow_EditLights_Reload_f(void);
355 void R_Shadow_ValidateCvars(void);
356 static void R_Shadow_MakeTextures(void);
358 // VorteX: custom editor light sprites
359 #define EDLIGHTSPRSIZE 8
360 cachepic_t *r_editlights_sprcursor;
361 cachepic_t *r_editlights_sprlight;
362 cachepic_t *r_editlights_sprnoshadowlight;
363 cachepic_t *r_editlights_sprcubemaplight;
364 cachepic_t *r_editlights_sprcubemapnoshadowlight;
365 cachepic_t *r_editlights_sprselection;
367 void R_Shadow_SetShadowMode(void)
369 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
370 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
371 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
372 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
373 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
374 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
375 r_shadow_shadowmaplod = -1;
376 r_shadow_shadowmapsize = 0;
377 r_shadow_shadowmapsampler = false;
378 r_shadow_shadowmappcf = 0;
379 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
380 if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
382 if(r_shadow_shadowmapfilterquality < 0)
384 if(strstr(gl_vendor, "NVIDIA"))
386 r_shadow_shadowmapsampler = gl_support_arb_shadow;
387 r_shadow_shadowmappcf = 1;
389 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
390 r_shadow_shadowmappcf = 1;
391 else if(strstr(gl_vendor, "ATI"))
392 r_shadow_shadowmappcf = 1;
394 r_shadow_shadowmapsampler = gl_support_arb_shadow;
398 switch (r_shadow_shadowmapfilterquality)
401 r_shadow_shadowmapsampler = gl_support_arb_shadow;
404 r_shadow_shadowmapsampler = gl_support_arb_shadow;
405 r_shadow_shadowmappcf = 1;
408 r_shadow_shadowmappcf = 1;
411 r_shadow_shadowmappcf = 2;
415 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
416 switch (r_shadow_shadowmaptexturetype)
419 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
422 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
425 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
428 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
429 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
430 else if(gl_texturerectangle)
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
433 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 void R_Shadow_FreeShadowMaps(void)
443 R_Shadow_SetShadowMode();
445 if (r_shadow_fborectangle)
446 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
447 r_shadow_fborectangle = 0;
451 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
454 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
455 if (r_shadow_fbocubeside[i])
456 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
457 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
460 if (r_shadow_shadowmaprectangletexture)
461 R_FreeTexture(r_shadow_shadowmaprectangletexture);
462 r_shadow_shadowmaprectangletexture = NULL;
464 if (r_shadow_shadowmap2dtexture)
465 R_FreeTexture(r_shadow_shadowmap2dtexture);
466 r_shadow_shadowmap2dtexture = NULL;
468 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
469 if (r_shadow_shadowmapcubetexture[i])
470 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
471 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
473 if (r_shadow_shadowmapvsdcttexture)
474 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
475 r_shadow_shadowmapvsdcttexture = NULL;
480 void r_shadow_start(void)
482 // allocate vertex processing arrays
484 r_shadow_attenuationgradienttexture = NULL;
485 r_shadow_attenuation2dtexture = NULL;
486 r_shadow_attenuation3dtexture = NULL;
487 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
488 r_shadow_shadowmaprectangletexture = NULL;
489 r_shadow_shadowmap2dtexture = NULL;
490 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
491 r_shadow_shadowmapvsdcttexture = NULL;
492 r_shadow_shadowmapmaxsize = 0;
493 r_shadow_shadowmapsize = 0;
494 r_shadow_shadowmaplod = 0;
495 r_shadow_shadowmapfilterquality = 0;
496 r_shadow_shadowmaptexturetype = 0;
497 r_shadow_shadowmapprecision = 0;
498 r_shadow_shadowmapvsdct = false;
499 r_shadow_shadowmapsampler = false;
500 r_shadow_shadowmappcf = 0;
501 r_shadow_fborectangle = 0;
503 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
505 R_Shadow_FreeShadowMaps();
507 r_shadow_texturepool = NULL;
508 r_shadow_filters_texturepool = NULL;
509 R_Shadow_ValidateCvars();
510 R_Shadow_MakeTextures();
511 maxshadowtriangles = 0;
512 shadowelements = NULL;
513 maxshadowvertices = 0;
514 shadowvertex3f = NULL;
522 shadowmarklist = NULL;
527 shadowsideslist = NULL;
528 r_shadow_buffer_numleafpvsbytes = 0;
529 r_shadow_buffer_visitingleafpvs = NULL;
530 r_shadow_buffer_leafpvs = NULL;
531 r_shadow_buffer_leaflist = NULL;
532 r_shadow_buffer_numsurfacepvsbytes = 0;
533 r_shadow_buffer_surfacepvs = NULL;
534 r_shadow_buffer_surfacelist = NULL;
535 r_shadow_buffer_surfacesides = NULL;
536 r_shadow_buffer_numshadowtrispvsbytes = 0;
537 r_shadow_buffer_shadowtrispvs = NULL;
538 r_shadow_buffer_numlighttrispvsbytes = 0;
539 r_shadow_buffer_lighttrispvs = NULL;
542 void r_shadow_shutdown(void)
545 R_Shadow_UncompileWorldLights();
547 R_Shadow_FreeShadowMaps();
551 r_shadow_attenuationgradienttexture = NULL;
552 r_shadow_attenuation2dtexture = NULL;
553 r_shadow_attenuation3dtexture = NULL;
554 R_FreeTexturePool(&r_shadow_texturepool);
555 R_FreeTexturePool(&r_shadow_filters_texturepool);
556 maxshadowtriangles = 0;
558 Mem_Free(shadowelements);
559 shadowelements = NULL;
561 Mem_Free(shadowvertex3f);
562 shadowvertex3f = NULL;
565 Mem_Free(vertexupdate);
568 Mem_Free(vertexremap);
574 Mem_Free(shadowmark);
577 Mem_Free(shadowmarklist);
578 shadowmarklist = NULL;
583 Mem_Free(shadowsides);
586 Mem_Free(shadowsideslist);
587 shadowsideslist = NULL;
588 r_shadow_buffer_numleafpvsbytes = 0;
589 if (r_shadow_buffer_visitingleafpvs)
590 Mem_Free(r_shadow_buffer_visitingleafpvs);
591 r_shadow_buffer_visitingleafpvs = NULL;
592 if (r_shadow_buffer_leafpvs)
593 Mem_Free(r_shadow_buffer_leafpvs);
594 r_shadow_buffer_leafpvs = NULL;
595 if (r_shadow_buffer_leaflist)
596 Mem_Free(r_shadow_buffer_leaflist);
597 r_shadow_buffer_leaflist = NULL;
598 r_shadow_buffer_numsurfacepvsbytes = 0;
599 if (r_shadow_buffer_surfacepvs)
600 Mem_Free(r_shadow_buffer_surfacepvs);
601 r_shadow_buffer_surfacepvs = NULL;
602 if (r_shadow_buffer_surfacelist)
603 Mem_Free(r_shadow_buffer_surfacelist);
604 r_shadow_buffer_surfacelist = NULL;
605 if (r_shadow_buffer_surfacesides)
606 Mem_Free(r_shadow_buffer_surfacesides);
607 r_shadow_buffer_surfacesides = NULL;
608 r_shadow_buffer_numshadowtrispvsbytes = 0;
609 if (r_shadow_buffer_shadowtrispvs)
610 Mem_Free(r_shadow_buffer_shadowtrispvs);
611 r_shadow_buffer_numlighttrispvsbytes = 0;
612 if (r_shadow_buffer_lighttrispvs)
613 Mem_Free(r_shadow_buffer_lighttrispvs);
616 void r_shadow_newmap(void)
618 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
619 R_Shadow_EditLights_Reload_f();
622 void R_Shadow_Help_f(void)
625 "Documentation on r_shadow system:\n"
627 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
628 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
629 "r_shadow_debuglight : render only this light number (-1 = all)\n"
630 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
631 "r_shadow_gloss2intensity : brightness of forced gloss\n"
632 "r_shadow_glossintensity : brightness of textured gloss\n"
633 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
634 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
635 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
636 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
637 "r_shadow_portallight : use portal visibility for static light precomputation\n"
638 "r_shadow_projectdistance : shadow volume projection distance\n"
639 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
640 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
641 "r_shadow_realtime_world : use high quality world lighting mode\n"
642 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
643 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
644 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
645 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
646 "r_shadow_scissor : use scissor optimization\n"
647 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
648 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
649 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
650 "r_showlighting : useful for performance testing; bright = slow!\n"
651 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
653 "r_shadow_help : this help\n"
657 void R_Shadow_Init(void)
659 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
660 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
661 Cvar_RegisterVariable(&r_shadow_usenormalmap);
662 Cvar_RegisterVariable(&r_shadow_debuglight);
663 Cvar_RegisterVariable(&r_shadow_gloss);
664 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
665 Cvar_RegisterVariable(&r_shadow_glossintensity);
666 Cvar_RegisterVariable(&r_shadow_glossexponent);
667 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
668 Cvar_RegisterVariable(&r_shadow_glossexact);
669 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
670 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
671 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
672 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
673 Cvar_RegisterVariable(&r_shadow_portallight);
674 Cvar_RegisterVariable(&r_shadow_projectdistance);
675 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
676 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
677 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
678 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
679 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
680 Cvar_RegisterVariable(&r_shadow_realtime_world);
681 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
682 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
683 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
684 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
685 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
686 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
687 Cvar_RegisterVariable(&r_shadow_scissor);
688 Cvar_RegisterVariable(&r_shadow_shadowmapping);
689 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
690 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
691 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
692 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
693 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
694 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
695 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
700 Cvar_RegisterVariable(&r_shadow_culltriangles);
701 Cvar_RegisterVariable(&r_shadow_polygonfactor);
702 Cvar_RegisterVariable(&r_shadow_polygonoffset);
703 Cvar_RegisterVariable(&r_shadow_texture3d);
704 Cvar_RegisterVariable(&r_coronas);
705 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
706 Cvar_RegisterVariable(&r_coronas_occlusionquery);
707 Cvar_RegisterVariable(&gl_flashblend);
708 Cvar_RegisterVariable(&gl_ext_separatestencil);
709 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
710 if (gamemode == GAME_TENEBRAE)
712 Cvar_SetValue("r_shadow_gloss", 2);
713 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
715 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
716 R_Shadow_EditLights_Init();
717 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
718 maxshadowtriangles = 0;
719 shadowelements = NULL;
720 maxshadowvertices = 0;
721 shadowvertex3f = NULL;
729 shadowmarklist = NULL;
734 shadowsideslist = NULL;
735 r_shadow_buffer_numleafpvsbytes = 0;
736 r_shadow_buffer_visitingleafpvs = NULL;
737 r_shadow_buffer_leafpvs = NULL;
738 r_shadow_buffer_leaflist = NULL;
739 r_shadow_buffer_numsurfacepvsbytes = 0;
740 r_shadow_buffer_surfacepvs = NULL;
741 r_shadow_buffer_surfacelist = NULL;
742 r_shadow_buffer_surfacesides = NULL;
743 r_shadow_buffer_shadowtrispvs = NULL;
744 r_shadow_buffer_lighttrispvs = NULL;
745 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
748 matrix4x4_t matrix_attenuationxyz =
751 {0.5, 0.0, 0.0, 0.5},
752 {0.0, 0.5, 0.0, 0.5},
753 {0.0, 0.0, 0.5, 0.5},
758 matrix4x4_t matrix_attenuationz =
761 {0.0, 0.0, 0.5, 0.5},
762 {0.0, 0.0, 0.0, 0.5},
763 {0.0, 0.0, 0.0, 0.5},
768 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
770 numvertices = ((numvertices + 255) & ~255) * vertscale;
771 numtriangles = ((numtriangles + 255) & ~255) * triscale;
772 // make sure shadowelements is big enough for this volume
773 if (maxshadowtriangles < numtriangles)
775 maxshadowtriangles = numtriangles;
777 Mem_Free(shadowelements);
778 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
780 // make sure shadowvertex3f is big enough for this volume
781 if (maxshadowvertices < numvertices)
783 maxshadowvertices = numvertices;
785 Mem_Free(shadowvertex3f);
786 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
790 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
792 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
793 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
794 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
795 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
796 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
798 if (r_shadow_buffer_visitingleafpvs)
799 Mem_Free(r_shadow_buffer_visitingleafpvs);
800 if (r_shadow_buffer_leafpvs)
801 Mem_Free(r_shadow_buffer_leafpvs);
802 if (r_shadow_buffer_leaflist)
803 Mem_Free(r_shadow_buffer_leaflist);
804 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
805 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
806 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
807 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
809 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
811 if (r_shadow_buffer_surfacepvs)
812 Mem_Free(r_shadow_buffer_surfacepvs);
813 if (r_shadow_buffer_surfacelist)
814 Mem_Free(r_shadow_buffer_surfacelist);
815 if (r_shadow_buffer_surfacesides)
816 Mem_Free(r_shadow_buffer_surfacesides);
817 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
818 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
819 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
820 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
822 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
824 if (r_shadow_buffer_shadowtrispvs)
825 Mem_Free(r_shadow_buffer_shadowtrispvs);
826 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
827 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
829 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
831 if (r_shadow_buffer_lighttrispvs)
832 Mem_Free(r_shadow_buffer_lighttrispvs);
833 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
834 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
838 void R_Shadow_PrepareShadowMark(int numtris)
840 // make sure shadowmark is big enough for this volume
841 if (maxshadowmark < numtris)
843 maxshadowmark = numtris;
845 Mem_Free(shadowmark);
847 Mem_Free(shadowmarklist);
848 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
849 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
853 // if shadowmarkcount wrapped we clear the array and adjust accordingly
854 if (shadowmarkcount == 0)
857 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
862 void R_Shadow_PrepareShadowSides(int numtris)
864 if (maxshadowsides < numtris)
866 maxshadowsides = numtris;
868 Mem_Free(shadowsides);
870 Mem_Free(shadowsideslist);
871 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
872 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
877 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)
880 int outtriangles = 0, outvertices = 0;
883 float ratio, direction[3], projectvector[3];
885 if (projectdirection)
886 VectorScale(projectdirection, projectdistance, projectvector);
888 VectorClear(projectvector);
890 // create the vertices
891 if (projectdirection)
893 for (i = 0;i < numshadowmarktris;i++)
895 element = inelement3i + shadowmarktris[i] * 3;
896 for (j = 0;j < 3;j++)
898 if (vertexupdate[element[j]] != vertexupdatenum)
900 vertexupdate[element[j]] = vertexupdatenum;
901 vertexremap[element[j]] = outvertices;
902 vertex = invertex3f + element[j] * 3;
903 // project one copy of the vertex according to projectvector
904 VectorCopy(vertex, outvertex3f);
905 VectorAdd(vertex, projectvector, (outvertex3f + 3));
914 for (i = 0;i < numshadowmarktris;i++)
916 element = inelement3i + shadowmarktris[i] * 3;
917 for (j = 0;j < 3;j++)
919 if (vertexupdate[element[j]] != vertexupdatenum)
921 vertexupdate[element[j]] = vertexupdatenum;
922 vertexremap[element[j]] = outvertices;
923 vertex = invertex3f + element[j] * 3;
924 // project one copy of the vertex to the sphere radius of the light
925 // (FIXME: would projecting it to the light box be better?)
926 VectorSubtract(vertex, projectorigin, direction);
927 ratio = projectdistance / VectorLength(direction);
928 VectorCopy(vertex, outvertex3f);
929 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
937 if (r_shadow_frontsidecasting.integer)
939 for (i = 0;i < numshadowmarktris;i++)
941 int remappedelement[3];
943 const int *neighbortriangle;
945 markindex = shadowmarktris[i] * 3;
946 element = inelement3i + markindex;
947 neighbortriangle = inneighbor3i + markindex;
948 // output the front and back triangles
949 outelement3i[0] = vertexremap[element[0]];
950 outelement3i[1] = vertexremap[element[1]];
951 outelement3i[2] = vertexremap[element[2]];
952 outelement3i[3] = vertexremap[element[2]] + 1;
953 outelement3i[4] = vertexremap[element[1]] + 1;
954 outelement3i[5] = vertexremap[element[0]] + 1;
958 // output the sides (facing outward from this triangle)
959 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
961 remappedelement[0] = vertexremap[element[0]];
962 remappedelement[1] = vertexremap[element[1]];
963 outelement3i[0] = remappedelement[1];
964 outelement3i[1] = remappedelement[0];
965 outelement3i[2] = remappedelement[0] + 1;
966 outelement3i[3] = remappedelement[1];
967 outelement3i[4] = remappedelement[0] + 1;
968 outelement3i[5] = remappedelement[1] + 1;
973 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
975 remappedelement[1] = vertexremap[element[1]];
976 remappedelement[2] = vertexremap[element[2]];
977 outelement3i[0] = remappedelement[2];
978 outelement3i[1] = remappedelement[1];
979 outelement3i[2] = remappedelement[1] + 1;
980 outelement3i[3] = remappedelement[2];
981 outelement3i[4] = remappedelement[1] + 1;
982 outelement3i[5] = remappedelement[2] + 1;
987 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
989 remappedelement[0] = vertexremap[element[0]];
990 remappedelement[2] = vertexremap[element[2]];
991 outelement3i[0] = remappedelement[0];
992 outelement3i[1] = remappedelement[2];
993 outelement3i[2] = remappedelement[2] + 1;
994 outelement3i[3] = remappedelement[0];
995 outelement3i[4] = remappedelement[2] + 1;
996 outelement3i[5] = remappedelement[0] + 1;
1005 for (i = 0;i < numshadowmarktris;i++)
1007 int remappedelement[3];
1009 const int *neighbortriangle;
1011 markindex = shadowmarktris[i] * 3;
1012 element = inelement3i + markindex;
1013 neighbortriangle = inneighbor3i + markindex;
1014 // output the front and back triangles
1015 outelement3i[0] = vertexremap[element[2]];
1016 outelement3i[1] = vertexremap[element[1]];
1017 outelement3i[2] = vertexremap[element[0]];
1018 outelement3i[3] = vertexremap[element[0]] + 1;
1019 outelement3i[4] = vertexremap[element[1]] + 1;
1020 outelement3i[5] = vertexremap[element[2]] + 1;
1024 // output the sides (facing outward from this triangle)
1025 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1027 remappedelement[0] = vertexremap[element[0]];
1028 remappedelement[1] = vertexremap[element[1]];
1029 outelement3i[0] = remappedelement[0];
1030 outelement3i[1] = remappedelement[1];
1031 outelement3i[2] = remappedelement[1] + 1;
1032 outelement3i[3] = remappedelement[0];
1033 outelement3i[4] = remappedelement[1] + 1;
1034 outelement3i[5] = remappedelement[0] + 1;
1039 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1041 remappedelement[1] = vertexremap[element[1]];
1042 remappedelement[2] = vertexremap[element[2]];
1043 outelement3i[0] = remappedelement[1];
1044 outelement3i[1] = remappedelement[2];
1045 outelement3i[2] = remappedelement[2] + 1;
1046 outelement3i[3] = remappedelement[1];
1047 outelement3i[4] = remappedelement[2] + 1;
1048 outelement3i[5] = remappedelement[1] + 1;
1053 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1055 remappedelement[0] = vertexremap[element[0]];
1056 remappedelement[2] = vertexremap[element[2]];
1057 outelement3i[0] = remappedelement[2];
1058 outelement3i[1] = remappedelement[0];
1059 outelement3i[2] = remappedelement[0] + 1;
1060 outelement3i[3] = remappedelement[2];
1061 outelement3i[4] = remappedelement[0] + 1;
1062 outelement3i[5] = remappedelement[2] + 1;
1070 *outnumvertices = outvertices;
1071 return outtriangles;
1074 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)
1077 int outtriangles = 0, outvertices = 0;
1079 const float *vertex;
1080 float ratio, direction[3], projectvector[3];
1083 if (projectdirection)
1084 VectorScale(projectdirection, projectdistance, projectvector);
1086 VectorClear(projectvector);
1088 for (i = 0;i < numshadowmarktris;i++)
1090 int remappedelement[3];
1092 const int *neighbortriangle;
1094 markindex = shadowmarktris[i] * 3;
1095 neighbortriangle = inneighbor3i + markindex;
1096 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1097 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1098 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1099 if (side[0] + side[1] + side[2] == 0)
1103 element = inelement3i + markindex;
1105 // create the vertices
1106 for (j = 0;j < 3;j++)
1108 if (side[j] + side[j+1] == 0)
1111 if (vertexupdate[k] != vertexupdatenum)
1113 vertexupdate[k] = vertexupdatenum;
1114 vertexremap[k] = outvertices;
1115 vertex = invertex3f + k * 3;
1116 VectorCopy(vertex, outvertex3f);
1117 if (projectdirection)
1119 // project one copy of the vertex according to projectvector
1120 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1124 // project one copy of the vertex to the sphere radius of the light
1125 // (FIXME: would projecting it to the light box be better?)
1126 VectorSubtract(vertex, projectorigin, direction);
1127 ratio = projectdistance / VectorLength(direction);
1128 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1135 // output the sides (facing outward from this triangle)
1138 remappedelement[0] = vertexremap[element[0]];
1139 remappedelement[1] = vertexremap[element[1]];
1140 outelement3i[0] = remappedelement[1];
1141 outelement3i[1] = remappedelement[0];
1142 outelement3i[2] = remappedelement[0] + 1;
1143 outelement3i[3] = remappedelement[1];
1144 outelement3i[4] = remappedelement[0] + 1;
1145 outelement3i[5] = remappedelement[1] + 1;
1152 remappedelement[1] = vertexremap[element[1]];
1153 remappedelement[2] = vertexremap[element[2]];
1154 outelement3i[0] = remappedelement[2];
1155 outelement3i[1] = remappedelement[1];
1156 outelement3i[2] = remappedelement[1] + 1;
1157 outelement3i[3] = remappedelement[2];
1158 outelement3i[4] = remappedelement[1] + 1;
1159 outelement3i[5] = remappedelement[2] + 1;
1166 remappedelement[0] = vertexremap[element[0]];
1167 remappedelement[2] = vertexremap[element[2]];
1168 outelement3i[0] = remappedelement[0];
1169 outelement3i[1] = remappedelement[2];
1170 outelement3i[2] = remappedelement[2] + 1;
1171 outelement3i[3] = remappedelement[0];
1172 outelement3i[4] = remappedelement[2] + 1;
1173 outelement3i[5] = remappedelement[0] + 1;
1180 *outnumvertices = outvertices;
1181 return outtriangles;
1184 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)
1190 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1192 tend = firsttriangle + numtris;
1193 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1195 // surface box entirely inside light box, no box cull
1196 if (projectdirection)
1198 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1200 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1201 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1202 shadowmarklist[numshadowmark++] = t;
1207 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1208 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1209 shadowmarklist[numshadowmark++] = t;
1214 // surface box not entirely inside light box, cull each triangle
1215 if (projectdirection)
1217 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1219 v[0] = invertex3f + e[0] * 3;
1220 v[1] = invertex3f + e[1] * 3;
1221 v[2] = invertex3f + e[2] * 3;
1222 TriangleNormal(v[0], v[1], v[2], normal);
1223 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1224 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1225 shadowmarklist[numshadowmark++] = t;
1230 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1232 v[0] = invertex3f + e[0] * 3;
1233 v[1] = invertex3f + e[1] * 3;
1234 v[2] = invertex3f + e[2] * 3;
1235 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1236 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1237 shadowmarklist[numshadowmark++] = t;
1243 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1248 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1250 // check if the shadow volume intersects the near plane
1252 // a ray between the eye and light origin may intersect the caster,
1253 // indicating that the shadow may touch the eye location, however we must
1254 // test the near plane (a polygon), not merely the eye location, so it is
1255 // easiest to enlarge the caster bounding shape slightly for this.
1261 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)
1263 int i, tris, outverts;
1264 if (projectdistance < 0.1)
1266 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1269 if (!numverts || !nummarktris)
1271 // make sure shadowelements is big enough for this volume
1272 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1273 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1275 if (maxvertexupdate < numverts)
1277 maxvertexupdate = numverts;
1279 Mem_Free(vertexupdate);
1281 Mem_Free(vertexremap);
1282 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1283 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1284 vertexupdatenum = 0;
1287 if (vertexupdatenum == 0)
1289 vertexupdatenum = 1;
1290 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1291 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1294 for (i = 0;i < nummarktris;i++)
1295 shadowmark[marktris[i]] = shadowmarkcount;
1297 if (r_shadow_compilingrtlight)
1299 // if we're compiling an rtlight, capture the mesh
1300 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1301 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1302 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1303 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1307 // decide which type of shadow to generate and set stencil mode
1308 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1309 // generate the sides or a solid volume, depending on type
1310 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1311 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1313 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1314 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1315 r_refdef.stats.lights_shadowtriangles += tris;
1317 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1318 GL_LockArrays(0, outverts);
1319 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1321 // increment stencil if frontface is infront of depthbuffer
1322 GL_CullFace(r_refdef.view.cullface_front);
1323 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1324 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1325 // decrement stencil if backface is infront of depthbuffer
1326 GL_CullFace(r_refdef.view.cullface_back);
1327 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1329 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1331 // decrement stencil if backface is behind depthbuffer
1332 GL_CullFace(r_refdef.view.cullface_front);
1333 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1334 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1335 // increment stencil if frontface is behind depthbuffer
1336 GL_CullFace(r_refdef.view.cullface_back);
1337 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1339 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1340 GL_LockArrays(0, 0);
1345 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1347 // p1, p2, p3 are in the cubemap's local coordinate system
1348 // bias = border/(size - border)
1351 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1352 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1353 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1354 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1356 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1357 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1358 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1359 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1361 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1362 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1363 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1365 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1366 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1367 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1368 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1370 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1371 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1372 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1373 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1375 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1376 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1377 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1379 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1380 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1381 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1382 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1384 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1385 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1386 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1387 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1389 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1390 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1391 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1396 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1398 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1399 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1402 VectorSubtract(maxs, mins, radius);
1403 VectorScale(radius, 0.5f, radius);
1404 VectorAdd(mins, radius, center);
1405 Matrix4x4_Transform(worldtolight, center, lightcenter);
1406 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1407 VectorSubtract(lightcenter, lightradius, pmin);
1408 VectorAdd(lightcenter, lightradius, pmax);
1410 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1411 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1412 if(ap1 > bias*an1 && ap2 > bias*an2)
1414 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1415 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1416 if(an1 > bias*ap1 && an2 > bias*ap2)
1418 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1419 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1421 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1422 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1423 if(ap1 > bias*an1 && ap2 > bias*an2)
1425 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1426 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1427 if(an1 > bias*ap1 && an2 > bias*ap2)
1429 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1430 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1432 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1433 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1434 if(ap1 > bias*an1 && ap2 > bias*an2)
1436 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1437 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1438 if(an1 > bias*ap1 && an2 > bias*ap2)
1440 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1441 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1446 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1448 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1450 // p is in the cubemap's local coordinate system
1451 // bias = border/(size - border)
1452 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1453 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1454 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1456 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1457 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1458 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1459 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1460 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1461 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1465 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1469 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1470 float scale = (size - 2*border)/size, len;
1471 float bias = border / (float)(size - border), dp, dn, ap, an;
1472 // check if cone enclosing side would cross frustum plane
1473 scale = 2 / (scale*scale + 2);
1474 for (i = 0;i < 5;i++)
1476 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1478 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1479 len = scale*VectorLength2(n);
1480 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1481 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1482 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1484 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1486 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1487 len = scale*VectorLength(n);
1488 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1489 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1490 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1492 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1493 // check if frustum corners/origin cross plane sides
1494 for (i = 0;i < 5;i++)
1496 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1497 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1498 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1499 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1500 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1501 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1502 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1503 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1504 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1505 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1507 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1510 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1518 int mask, surfacemask = 0;
1519 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1521 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1522 tend = firsttriangle + numtris;
1523 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1525 // surface box entirely inside light box, no box cull
1526 if (projectdirection)
1528 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1530 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1531 TriangleNormal(v[0], v[1], v[2], normal);
1532 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1534 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1535 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1536 surfacemask |= mask;
1539 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1540 shadowsides[numshadowsides] = mask;
1541 shadowsideslist[numshadowsides++] = t;
1548 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1550 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1551 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1553 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1554 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1555 surfacemask |= mask;
1558 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1559 shadowsides[numshadowsides] = mask;
1560 shadowsideslist[numshadowsides++] = t;
1568 // surface box not entirely inside light box, cull each triangle
1569 if (projectdirection)
1571 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1573 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1574 TriangleNormal(v[0], v[1], v[2], normal);
1575 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1576 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1578 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1579 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1580 surfacemask |= mask;
1583 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1584 shadowsides[numshadowsides] = mask;
1585 shadowsideslist[numshadowsides++] = t;
1592 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1594 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1595 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1596 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1598 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1599 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1600 surfacemask |= mask;
1603 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1604 shadowsides[numshadowsides] = mask;
1605 shadowsideslist[numshadowsides++] = t;
1614 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1616 int i, j, outtriangles = 0;
1617 int *outelement3i[6];
1618 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1620 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1621 // make sure shadowelements is big enough for this mesh
1622 if (maxshadowtriangles < outtriangles)
1623 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1625 // compute the offset and size of the separate index lists for each cubemap side
1627 for (i = 0;i < 6;i++)
1629 outelement3i[i] = shadowelements + outtriangles * 3;
1630 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1631 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1632 outtriangles += sidetotals[i];
1635 // gather up the (sparse) triangles into separate index lists for each cubemap side
1636 for (i = 0;i < numsidetris;i++)
1638 const int *element = elements + sidetris[i] * 3;
1639 for (j = 0;j < 6;j++)
1641 if (sides[i] & (1 << j))
1643 outelement3i[j][0] = element[0];
1644 outelement3i[j][1] = element[1];
1645 outelement3i[j][2] = element[2];
1646 outelement3i[j] += 3;
1651 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1654 static void R_Shadow_MakeTextures_MakeCorona(void)
1658 unsigned char pixels[32][32][4];
1659 for (y = 0;y < 32;y++)
1661 dy = (y - 15.5f) * (1.0f / 16.0f);
1662 for (x = 0;x < 32;x++)
1664 dx = (x - 15.5f) * (1.0f / 16.0f);
1665 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1666 a = bound(0, a, 255);
1667 pixels[y][x][0] = a;
1668 pixels[y][x][1] = a;
1669 pixels[y][x][2] = a;
1670 pixels[y][x][3] = 255;
1673 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1676 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1678 float dist = sqrt(x*x+y*y+z*z);
1679 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1680 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1681 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1684 static void R_Shadow_MakeTextures(void)
1687 float intensity, dist;
1689 R_FreeTexturePool(&r_shadow_texturepool);
1690 r_shadow_texturepool = R_AllocTexturePool();
1691 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1692 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1693 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1694 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1695 for (x = 0;x <= ATTENTABLESIZE;x++)
1697 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1698 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1699 r_shadow_attentable[x] = bound(0, intensity, 1);
1701 // 1D gradient texture
1702 for (x = 0;x < ATTEN1DSIZE;x++)
1703 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1704 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);
1705 // 2D circle texture
1706 for (y = 0;y < ATTEN2DSIZE;y++)
1707 for (x = 0;x < ATTEN2DSIZE;x++)
1708 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);
1709 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);
1710 // 3D sphere texture
1711 if (r_shadow_texture3d.integer && gl_texture3d)
1713 for (z = 0;z < ATTEN3DSIZE;z++)
1714 for (y = 0;y < ATTEN3DSIZE;y++)
1715 for (x = 0;x < ATTEN3DSIZE;x++)
1716 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));
1717 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);
1720 r_shadow_attenuation3dtexture = NULL;
1723 R_Shadow_MakeTextures_MakeCorona();
1725 // Editor light sprites
1726 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1727 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1728 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1729 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1730 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1731 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1734 void R_Shadow_ValidateCvars(void)
1736 if (r_shadow_texture3d.integer && !gl_texture3d)
1737 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1738 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1739 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1740 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1741 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1744 void R_Shadow_RenderMode_Begin(void)
1750 R_Shadow_ValidateCvars();
1752 if (!r_shadow_attenuation2dtexture
1753 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1754 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1755 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1756 R_Shadow_MakeTextures();
1759 R_Mesh_ColorPointer(NULL, 0, 0);
1760 R_Mesh_ResetTextureState();
1761 GL_BlendFunc(GL_ONE, GL_ZERO);
1762 GL_DepthRange(0, 1);
1763 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1765 GL_DepthMask(false);
1766 GL_Color(0, 0, 0, 1);
1767 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1769 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1771 if (gl_ext_separatestencil.integer)
1773 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1774 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1776 else if (gl_ext_stenciltwoside.integer)
1778 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1779 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1783 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1784 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1787 if (r_glsl.integer && gl_support_fragment_shader)
1788 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1789 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1790 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1792 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1796 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1797 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1798 r_shadow_drawbuffer = drawbuffer;
1799 r_shadow_readbuffer = readbuffer;
1801 r_shadow_cullface_front = r_refdef.view.cullface_front;
1802 r_shadow_cullface_back = r_refdef.view.cullface_back;
1805 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1807 rsurface.rtlight = rtlight;
1810 void R_Shadow_RenderMode_Reset(void)
1813 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1815 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1817 if (gl_support_ext_framebuffer_object)
1819 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1822 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1823 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1825 R_SetViewport(&r_refdef.view.viewport);
1826 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1827 R_Mesh_ColorPointer(NULL, 0, 0);
1828 R_Mesh_ResetTextureState();
1829 GL_DepthRange(0, 1);
1831 GL_DepthMask(false);
1832 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1833 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1834 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1835 qglStencilMask(~0);CHECKGLERROR
1836 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1837 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1838 r_refdef.view.cullface_front = r_shadow_cullface_front;
1839 r_refdef.view.cullface_back = r_shadow_cullface_back;
1840 GL_CullFace(r_refdef.view.cullface_back);
1841 GL_Color(1, 1, 1, 1);
1842 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1843 GL_BlendFunc(GL_ONE, GL_ZERO);
1844 R_SetupGenericShader(false);
1845 r_shadow_usingshadowmaprect = false;
1846 r_shadow_usingshadowmapcube = false;
1847 r_shadow_usingshadowmap2d = false;
1851 void R_Shadow_ClearStencil(void)
1854 GL_Clear(GL_STENCIL_BUFFER_BIT);
1855 r_refdef.stats.lights_clears++;
1858 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1860 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1861 if (r_shadow_rendermode == mode)
1864 R_Shadow_RenderMode_Reset();
1865 GL_ColorMask(0, 0, 0, 0);
1866 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1867 R_SetupDepthOrShadowShader();
1868 qglDepthFunc(GL_LESS);CHECKGLERROR
1869 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1870 r_shadow_rendermode = mode;
1875 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1876 GL_CullFace(GL_NONE);
1877 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1878 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1880 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1881 GL_CullFace(GL_NONE);
1882 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1883 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1885 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1886 GL_CullFace(GL_NONE);
1887 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1888 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1889 qglStencilMask(~0);CHECKGLERROR
1890 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1891 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1892 qglStencilMask(~0);CHECKGLERROR
1893 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1895 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1896 GL_CullFace(GL_NONE);
1897 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1898 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1899 qglStencilMask(~0);CHECKGLERROR
1900 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1901 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1902 qglStencilMask(~0);CHECKGLERROR
1903 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1908 static void R_Shadow_MakeVSDCT(void)
1910 // maps to a 2x3 texture rectangle with normalized coordinates
1915 // stores abs(dir.xy), offset.xy/2.5
1916 unsigned char data[4*6] =
1918 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1919 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1920 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1921 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1922 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1923 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1925 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1928 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1932 float nearclip, farclip, bias;
1933 r_viewport_t viewport;
1936 maxsize = r_shadow_shadowmapmaxsize;
1937 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1939 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1940 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1941 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1942 r_shadow_shadowmapside = side;
1943 r_shadow_shadowmapsize = size;
1944 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1946 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1947 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1948 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1949 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1951 // complex unrolled cube approach (more flexible)
1952 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1953 R_Shadow_MakeVSDCT();
1954 if (!r_shadow_shadowmap2dtexture)
1957 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1958 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1959 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1960 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1961 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1962 // render depth into the fbo, do not render color at all
1963 qglDrawBuffer(GL_NONE);CHECKGLERROR
1964 qglReadBuffer(GL_NONE);CHECKGLERROR
1965 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1966 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1968 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1969 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1974 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1975 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1976 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1977 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1979 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1981 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1982 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1983 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1984 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1986 // complex unrolled cube approach (more flexible)
1987 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1988 R_Shadow_MakeVSDCT();
1989 if (!r_shadow_shadowmaprectangletexture)
1992 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1993 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1994 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1995 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1996 // render depth into the fbo, do not render color at all
1997 qglDrawBuffer(GL_NONE);CHECKGLERROR
1998 qglReadBuffer(GL_NONE);CHECKGLERROR
1999 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2000 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2002 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2003 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2008 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2009 r_shadow_shadowmap_texturescale[0] = 1.0f;
2010 r_shadow_shadowmap_texturescale[1] = 1.0f;
2011 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2013 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2015 r_shadow_shadowmap_parameters[0] = 1.0f;
2016 r_shadow_shadowmap_parameters[1] = 1.0f;
2017 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2018 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2020 // simple cube approach
2021 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2024 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
2025 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2026 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2027 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2028 // render depth into the fbo, do not render color at all
2029 qglDrawBuffer(GL_NONE);CHECKGLERROR
2030 qglReadBuffer(GL_NONE);CHECKGLERROR
2031 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2032 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2034 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2035 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2040 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2041 r_shadow_shadowmap_texturescale[0] = 0.0f;
2042 r_shadow_shadowmap_texturescale[1] = 0.0f;
2043 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2046 R_Shadow_RenderMode_Reset();
2049 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2050 R_SetupDepthOrShadowShader();
2054 R_SetupShowDepthShader();
2055 qglClearColor(1,1,1,1);CHECKGLERROR
2058 GL_PolygonOffset(0, 0);
2065 R_SetViewport(&viewport);
2066 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2067 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2069 int flipped = (side&1)^(side>>2);
2070 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2071 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2072 GL_CullFace(r_refdef.view.cullface_back);
2074 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2076 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2079 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2083 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2086 R_Shadow_RenderMode_Reset();
2087 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2090 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2094 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2095 // only draw light where this geometry was already rendered AND the
2096 // stencil is 128 (values other than this mean shadow)
2097 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2099 r_shadow_rendermode = r_shadow_lightingrendermode;
2100 // do global setup needed for the chosen lighting mode
2101 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2103 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2104 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2108 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2110 r_shadow_usingshadowmap2d = true;
2111 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2114 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2116 r_shadow_usingshadowmaprect = true;
2117 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2120 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2122 r_shadow_usingshadowmapcube = true;
2123 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2127 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2129 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2134 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2135 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2136 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2140 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2143 R_Shadow_RenderMode_Reset();
2144 GL_BlendFunc(GL_ONE, GL_ONE);
2145 GL_DepthRange(0, 1);
2146 GL_DepthTest(r_showshadowvolumes.integer < 2);
2147 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2148 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2149 GL_CullFace(GL_NONE);
2150 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2153 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2156 R_Shadow_RenderMode_Reset();
2157 GL_BlendFunc(GL_ONE, GL_ONE);
2158 GL_DepthRange(0, 1);
2159 GL_DepthTest(r_showlighting.integer < 2);
2160 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2163 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2167 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2168 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2170 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2173 void R_Shadow_RenderMode_End(void)
2176 R_Shadow_RenderMode_Reset();
2177 R_Shadow_RenderMode_ActiveLight(NULL);
2179 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2180 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2183 int bboxedges[12][2] =
2202 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2204 int i, ix1, iy1, ix2, iy2;
2205 float x1, y1, x2, y2;
2207 float vertex[20][3];
2216 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2217 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2218 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2219 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2221 if (!r_shadow_scissor.integer)
2224 // if view is inside the light box, just say yes it's visible
2225 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2228 x1 = y1 = x2 = y2 = 0;
2230 // transform all corners that are infront of the nearclip plane
2231 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2232 plane4f[3] = r_refdef.view.frustum[4].dist;
2234 for (i = 0;i < 8;i++)
2236 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2237 dist[i] = DotProduct4(corner[i], plane4f);
2238 sign[i] = dist[i] > 0;
2241 VectorCopy(corner[i], vertex[numvertices]);
2245 // if some points are behind the nearclip, add clipped edge points to make
2246 // sure that the scissor boundary is complete
2247 if (numvertices > 0 && numvertices < 8)
2249 // add clipped edge points
2250 for (i = 0;i < 12;i++)
2252 j = bboxedges[i][0];
2253 k = bboxedges[i][1];
2254 if (sign[j] != sign[k])
2256 f = dist[j] / (dist[j] - dist[k]);
2257 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2263 // if we have no points to check, the light is behind the view plane
2267 // if we have some points to transform, check what screen area is covered
2268 x1 = y1 = x2 = y2 = 0;
2270 //Con_Printf("%i vertices to transform...\n", numvertices);
2271 for (i = 0;i < numvertices;i++)
2273 VectorCopy(vertex[i], v);
2274 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2275 //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]);
2278 if (x1 > v2[0]) x1 = v2[0];
2279 if (x2 < v2[0]) x2 = v2[0];
2280 if (y1 > v2[1]) y1 = v2[1];
2281 if (y2 < v2[1]) y2 = v2[1];
2290 // now convert the scissor rectangle to integer screen coordinates
2291 ix1 = (int)(x1 - 1.0f);
2292 iy1 = vid.height - (int)(y2 - 1.0f);
2293 ix2 = (int)(x2 + 1.0f);
2294 iy2 = vid.height - (int)(y1 + 1.0f);
2295 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2297 // clamp it to the screen
2298 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2299 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2300 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2301 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2303 // if it is inside out, it's not visible
2304 if (ix2 <= ix1 || iy2 <= iy1)
2307 // the light area is visible, set up the scissor rectangle
2308 r_shadow_lightscissor[0] = ix1;
2309 r_shadow_lightscissor[1] = iy1;
2310 r_shadow_lightscissor[2] = ix2 - ix1;
2311 r_shadow_lightscissor[3] = iy2 - iy1;
2313 r_refdef.stats.lights_scissored++;
2317 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2319 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2320 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2321 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2322 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2323 if (r_textureunits.integer >= 3)
2325 if (VectorLength2(diffusecolor) > 0)
2327 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2329 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2330 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2331 if ((dot = DotProduct(n, v)) < 0)
2333 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2334 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2337 VectorCopy(ambientcolor, color4f);
2338 if (r_refdef.fogenabled)
2341 f = FogPoint_Model(vertex3f);
2342 VectorScale(color4f, f, color4f);
2349 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2351 VectorCopy(ambientcolor, color4f);
2352 if (r_refdef.fogenabled)
2355 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2356 f = FogPoint_Model(vertex3f);
2357 VectorScale(color4f, f, color4f);
2363 else if (r_textureunits.integer >= 2)
2365 if (VectorLength2(diffusecolor) > 0)
2367 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2369 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2370 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2372 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2373 if ((dot = DotProduct(n, v)) < 0)
2375 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2376 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2377 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2378 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2382 color4f[0] = ambientcolor[0] * distintensity;
2383 color4f[1] = ambientcolor[1] * distintensity;
2384 color4f[2] = ambientcolor[2] * distintensity;
2386 if (r_refdef.fogenabled)
2389 f = FogPoint_Model(vertex3f);
2390 VectorScale(color4f, f, color4f);
2394 VectorClear(color4f);
2400 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2402 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2403 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2405 color4f[0] = ambientcolor[0] * distintensity;
2406 color4f[1] = ambientcolor[1] * distintensity;
2407 color4f[2] = ambientcolor[2] * distintensity;
2408 if (r_refdef.fogenabled)
2411 f = FogPoint_Model(vertex3f);
2412 VectorScale(color4f, f, color4f);
2416 VectorClear(color4f);
2423 if (VectorLength2(diffusecolor) > 0)
2425 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2427 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2428 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2430 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2431 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2432 if ((dot = DotProduct(n, v)) < 0)
2434 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2435 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2436 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2437 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2441 color4f[0] = ambientcolor[0] * distintensity;
2442 color4f[1] = ambientcolor[1] * distintensity;
2443 color4f[2] = ambientcolor[2] * distintensity;
2445 if (r_refdef.fogenabled)
2448 f = FogPoint_Model(vertex3f);
2449 VectorScale(color4f, f, color4f);
2453 VectorClear(color4f);
2459 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2461 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2462 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2464 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2465 color4f[0] = ambientcolor[0] * distintensity;
2466 color4f[1] = ambientcolor[1] * distintensity;
2467 color4f[2] = ambientcolor[2] * distintensity;
2468 if (r_refdef.fogenabled)
2471 f = FogPoint_Model(vertex3f);
2472 VectorScale(color4f, f, color4f);
2476 VectorClear(color4f);
2483 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2485 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2488 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2489 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2490 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2491 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2492 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2494 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2496 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2497 // the cubemap normalizes this for us
2498 out3f[0] = DotProduct(svector3f, lightdir);
2499 out3f[1] = DotProduct(tvector3f, lightdir);
2500 out3f[2] = DotProduct(normal3f, lightdir);
2504 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2507 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2508 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2509 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2510 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2511 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2512 float lightdir[3], eyedir[3], halfdir[3];
2513 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2515 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2516 VectorNormalize(lightdir);
2517 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2518 VectorNormalize(eyedir);
2519 VectorAdd(lightdir, eyedir, halfdir);
2520 // the cubemap normalizes this for us
2521 out3f[0] = DotProduct(svector3f, halfdir);
2522 out3f[1] = DotProduct(tvector3f, halfdir);
2523 out3f[2] = DotProduct(normal3f, halfdir);
2527 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)
2529 // used to display how many times a surface is lit for level design purposes
2530 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2533 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)
2535 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2536 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2537 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2538 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2540 R_Mesh_ColorPointer(NULL, 0, 0);
2541 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2542 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2543 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2544 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2545 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2546 if (rsurface.texture->backgroundcurrentskinframe)
2548 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2549 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2550 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2551 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2553 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2554 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2555 if(rsurface.texture->colormapping)
2557 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2558 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2560 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2561 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2562 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2563 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2564 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2565 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2567 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2569 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2570 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2572 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2576 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)
2578 // shared final code for all the dot3 layers
2580 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2581 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2583 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2584 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2588 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)
2591 // colorscale accounts for how much we multiply the brightness
2594 // mult is how many times the final pass of the lighting will be
2595 // performed to get more brightness than otherwise possible.
2597 // Limit mult to 64 for sanity sake.
2599 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2601 // 3 3D combine path (Geforce3, Radeon 8500)
2602 memset(&m, 0, sizeof(m));
2603 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2604 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2605 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2606 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2607 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2608 m.tex[1] = R_GetTexture(basetexture);
2609 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2610 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2611 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2612 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2613 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2614 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2615 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2616 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2617 m.texmatrix[2] = rsurface.entitytolight;
2618 GL_BlendFunc(GL_ONE, GL_ONE);
2620 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2622 // 2 3D combine path (Geforce3, original Radeon)
2623 memset(&m, 0, sizeof(m));
2624 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2625 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2626 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2627 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2628 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2629 m.tex[1] = R_GetTexture(basetexture);
2630 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2631 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2632 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2633 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2634 GL_BlendFunc(GL_ONE, GL_ONE);
2636 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2638 // 4 2D combine path (Geforce3, Radeon 8500)
2639 memset(&m, 0, sizeof(m));
2640 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2641 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2642 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2643 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2644 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2645 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2646 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2647 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2648 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2649 m.texmatrix[1] = rsurface.entitytoattenuationz;
2650 m.tex[2] = R_GetTexture(basetexture);
2651 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2652 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2653 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2654 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2655 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2657 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2658 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2659 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2660 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2661 m.texmatrix[3] = rsurface.entitytolight;
2663 GL_BlendFunc(GL_ONE, GL_ONE);
2665 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2667 // 3 2D combine path (Geforce3, original Radeon)
2668 memset(&m, 0, sizeof(m));
2669 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2670 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2671 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2672 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2673 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2674 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2675 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2676 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2677 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2678 m.texmatrix[1] = rsurface.entitytoattenuationz;
2679 m.tex[2] = R_GetTexture(basetexture);
2680 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2681 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2682 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2683 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2684 GL_BlendFunc(GL_ONE, GL_ONE);
2688 // 2/2/2 2D combine path (any dot3 card)
2689 memset(&m, 0, sizeof(m));
2690 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2691 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2692 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2693 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2694 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2695 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2696 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2697 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2698 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2699 m.texmatrix[1] = rsurface.entitytoattenuationz;
2700 R_Mesh_TextureState(&m);
2701 GL_ColorMask(0,0,0,1);
2702 GL_BlendFunc(GL_ONE, GL_ZERO);
2703 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2706 memset(&m, 0, sizeof(m));
2707 m.tex[0] = R_GetTexture(basetexture);
2708 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2709 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2710 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2711 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2712 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2714 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2715 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2716 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2717 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2718 m.texmatrix[1] = rsurface.entitytolight;
2720 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2722 // this final code is shared
2723 R_Mesh_TextureState(&m);
2724 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);
2727 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)
2730 // colorscale accounts for how much we multiply the brightness
2733 // mult is how many times the final pass of the lighting will be
2734 // performed to get more brightness than otherwise possible.
2736 // Limit mult to 64 for sanity sake.
2738 // generate normalization cubemap texcoords
2739 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2740 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2742 // 3/2 3D combine path (Geforce3, Radeon 8500)
2743 memset(&m, 0, sizeof(m));
2744 m.tex[0] = R_GetTexture(normalmaptexture);
2745 m.texcombinergb[0] = GL_REPLACE;
2746 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2747 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2748 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2749 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2750 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2751 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2752 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2753 m.pointer_texcoord_bufferobject[1] = 0;
2754 m.pointer_texcoord_bufferoffset[1] = 0;
2755 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2756 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2757 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2758 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2759 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2760 R_Mesh_TextureState(&m);
2761 GL_ColorMask(0,0,0,1);
2762 GL_BlendFunc(GL_ONE, GL_ZERO);
2763 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2766 memset(&m, 0, sizeof(m));
2767 m.tex[0] = R_GetTexture(basetexture);
2768 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2769 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2770 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2771 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2772 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2774 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2775 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2776 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2777 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2778 m.texmatrix[1] = rsurface.entitytolight;
2780 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2782 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2784 // 1/2/2 3D combine path (original Radeon)
2785 memset(&m, 0, sizeof(m));
2786 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2787 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2788 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2789 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2790 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2791 R_Mesh_TextureState(&m);
2792 GL_ColorMask(0,0,0,1);
2793 GL_BlendFunc(GL_ONE, GL_ZERO);
2794 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2797 memset(&m, 0, sizeof(m));
2798 m.tex[0] = R_GetTexture(normalmaptexture);
2799 m.texcombinergb[0] = GL_REPLACE;
2800 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2801 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2802 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2803 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2804 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2805 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2806 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2807 m.pointer_texcoord_bufferobject[1] = 0;
2808 m.pointer_texcoord_bufferoffset[1] = 0;
2809 R_Mesh_TextureState(&m);
2810 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2811 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2814 memset(&m, 0, sizeof(m));
2815 m.tex[0] = R_GetTexture(basetexture);
2816 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2817 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2818 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2819 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2820 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2822 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2823 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2824 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2825 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2826 m.texmatrix[1] = rsurface.entitytolight;
2828 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2830 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2832 // 2/2 3D combine path (original Radeon)
2833 memset(&m, 0, sizeof(m));
2834 m.tex[0] = R_GetTexture(normalmaptexture);
2835 m.texcombinergb[0] = GL_REPLACE;
2836 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2837 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2838 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2839 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2840 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2841 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2842 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2843 m.pointer_texcoord_bufferobject[1] = 0;
2844 m.pointer_texcoord_bufferoffset[1] = 0;
2845 R_Mesh_TextureState(&m);
2846 GL_ColorMask(0,0,0,1);
2847 GL_BlendFunc(GL_ONE, GL_ZERO);
2848 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2851 memset(&m, 0, sizeof(m));
2852 m.tex[0] = R_GetTexture(basetexture);
2853 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2854 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2855 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2856 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2857 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2858 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2859 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2860 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2861 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2862 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2864 else if (r_textureunits.integer >= 4)
2866 // 4/2 2D combine path (Geforce3, Radeon 8500)
2867 memset(&m, 0, sizeof(m));
2868 m.tex[0] = R_GetTexture(normalmaptexture);
2869 m.texcombinergb[0] = GL_REPLACE;
2870 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2871 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2872 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2873 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2874 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2875 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2876 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2877 m.pointer_texcoord_bufferobject[1] = 0;
2878 m.pointer_texcoord_bufferoffset[1] = 0;
2879 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2880 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2881 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2882 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2883 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2884 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2885 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2886 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2887 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2888 m.texmatrix[3] = rsurface.entitytoattenuationz;
2889 R_Mesh_TextureState(&m);
2890 GL_ColorMask(0,0,0,1);
2891 GL_BlendFunc(GL_ONE, GL_ZERO);
2892 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2895 memset(&m, 0, sizeof(m));
2896 m.tex[0] = R_GetTexture(basetexture);
2897 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2898 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2899 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2900 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2901 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2903 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2904 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2905 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2906 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2907 m.texmatrix[1] = rsurface.entitytolight;
2909 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2913 // 2/2/2 2D combine path (any dot3 card)
2914 memset(&m, 0, sizeof(m));
2915 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2916 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2917 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2918 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2919 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2920 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2921 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2922 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2923 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2924 m.texmatrix[1] = rsurface.entitytoattenuationz;
2925 R_Mesh_TextureState(&m);
2926 GL_ColorMask(0,0,0,1);
2927 GL_BlendFunc(GL_ONE, GL_ZERO);
2928 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2931 memset(&m, 0, sizeof(m));
2932 m.tex[0] = R_GetTexture(normalmaptexture);
2933 m.texcombinergb[0] = GL_REPLACE;
2934 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2935 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2936 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2937 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2938 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2939 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2940 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2941 m.pointer_texcoord_bufferobject[1] = 0;
2942 m.pointer_texcoord_bufferoffset[1] = 0;
2943 R_Mesh_TextureState(&m);
2944 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2945 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2948 memset(&m, 0, sizeof(m));
2949 m.tex[0] = R_GetTexture(basetexture);
2950 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2951 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2952 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2953 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2954 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2956 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2957 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2958 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2959 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2960 m.texmatrix[1] = rsurface.entitytolight;
2962 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2964 // this final code is shared
2965 R_Mesh_TextureState(&m);
2966 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);
2969 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)
2971 float glossexponent;
2973 // FIXME: detect blendsquare!
2974 //if (!gl_support_blendsquare)
2977 // generate normalization cubemap texcoords
2978 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2979 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2981 // 2/0/0/1/2 3D combine blendsquare path
2982 memset(&m, 0, sizeof(m));
2983 m.tex[0] = R_GetTexture(normalmaptexture);
2984 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2985 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2986 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2987 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2988 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2989 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2990 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2991 m.pointer_texcoord_bufferobject[1] = 0;
2992 m.pointer_texcoord_bufferoffset[1] = 0;
2993 R_Mesh_TextureState(&m);
2994 GL_ColorMask(0,0,0,1);
2995 // this squares the result
2996 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2997 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2999 // second and third pass
3000 R_Mesh_ResetTextureState();
3001 // square alpha in framebuffer a few times to make it shiny
3002 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3003 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3004 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3007 memset(&m, 0, sizeof(m));
3008 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3009 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3010 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3011 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3012 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3013 R_Mesh_TextureState(&m);
3014 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3015 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3018 memset(&m, 0, sizeof(m));
3019 m.tex[0] = R_GetTexture(glosstexture);
3020 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3021 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3022 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3023 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3024 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3026 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3027 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3028 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3029 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3030 m.texmatrix[1] = rsurface.entitytolight;
3032 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3034 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3036 // 2/0/0/2 3D combine blendsquare path
3037 memset(&m, 0, sizeof(m));
3038 m.tex[0] = R_GetTexture(normalmaptexture);
3039 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3040 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3041 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3042 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3043 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3044 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3045 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3046 m.pointer_texcoord_bufferobject[1] = 0;
3047 m.pointer_texcoord_bufferoffset[1] = 0;
3048 R_Mesh_TextureState(&m);
3049 GL_ColorMask(0,0,0,1);
3050 // this squares the result
3051 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3052 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3054 // second and third pass
3055 R_Mesh_ResetTextureState();
3056 // square alpha in framebuffer a few times to make it shiny
3057 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3058 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3059 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3062 memset(&m, 0, sizeof(m));
3063 m.tex[0] = R_GetTexture(glosstexture);
3064 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3065 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3066 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3067 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3068 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3069 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3070 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3071 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3072 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3073 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3077 // 2/0/0/2/2 2D combine blendsquare path
3078 memset(&m, 0, sizeof(m));
3079 m.tex[0] = R_GetTexture(normalmaptexture);
3080 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3081 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3082 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3083 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3084 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3085 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3086 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3087 m.pointer_texcoord_bufferobject[1] = 0;
3088 m.pointer_texcoord_bufferoffset[1] = 0;
3089 R_Mesh_TextureState(&m);
3090 GL_ColorMask(0,0,0,1);
3091 // this squares the result
3092 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3093 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3095 // second and third pass
3096 R_Mesh_ResetTextureState();
3097 // square alpha in framebuffer a few times to make it shiny
3098 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3099 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3100 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3103 memset(&m, 0, sizeof(m));
3104 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3105 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3106 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3107 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3108 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3109 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3110 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3111 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3112 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3113 m.texmatrix[1] = rsurface.entitytoattenuationz;
3114 R_Mesh_TextureState(&m);
3115 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3116 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3119 memset(&m, 0, sizeof(m));
3120 m.tex[0] = R_GetTexture(glosstexture);
3121 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3122 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3123 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3124 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3125 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3127 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3128 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3129 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3130 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3131 m.texmatrix[1] = rsurface.entitytolight;
3133 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3135 // this final code is shared
3136 R_Mesh_TextureState(&m);
3137 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);
3140 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)
3142 // ARB path (any Geforce, any Radeon)
3143 qboolean doambient = ambientscale > 0;
3144 qboolean dodiffuse = diffusescale > 0;
3145 qboolean dospecular = specularscale > 0;
3146 if (!doambient && !dodiffuse && !dospecular)
3148 R_Mesh_ColorPointer(NULL, 0, 0);
3150 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3152 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3156 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3158 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3163 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3165 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3168 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3171 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3178 int newnumtriangles;
3182 int maxtriangles = 4096;
3183 int newelements[4096*3];
3184 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3185 for (renders = 0;renders < 64;renders++)
3190 newnumtriangles = 0;
3192 // due to low fillrate on the cards this vertex lighting path is
3193 // designed for, we manually cull all triangles that do not
3194 // contain a lit vertex
3195 // this builds batches of triangles from multiple surfaces and
3196 // renders them at once
3197 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3199 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3201 if (newnumtriangles)
3203 newfirstvertex = min(newfirstvertex, e[0]);
3204 newlastvertex = max(newlastvertex, e[0]);
3208 newfirstvertex = e[0];
3209 newlastvertex = e[0];
3211 newfirstvertex = min(newfirstvertex, e[1]);
3212 newlastvertex = max(newlastvertex, e[1]);
3213 newfirstvertex = min(newfirstvertex, e[2]);
3214 newlastvertex = max(newlastvertex, e[2]);
3220 if (newnumtriangles >= maxtriangles)
3222 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3223 newnumtriangles = 0;
3229 if (newnumtriangles >= 1)
3231 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3234 // if we couldn't find any lit triangles, exit early
3237 // now reduce the intensity for the next overbright pass
3238 // we have to clamp to 0 here incase the drivers have improper
3239 // handling of negative colors
3240 // (some old drivers even have improper handling of >1 color)
3242 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3244 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3246 c[0] = max(0, c[0] - 1);
3247 c[1] = max(0, c[1] - 1);
3248 c[2] = max(0, c[2] - 1);
3260 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)
3262 // OpenGL 1.1 path (anything)
3263 float ambientcolorbase[3], diffusecolorbase[3];
3264 float ambientcolorpants[3], diffusecolorpants[3];
3265 float ambientcolorshirt[3], diffusecolorshirt[3];
3267 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3268 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3269 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3270 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3271 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3272 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3273 memset(&m, 0, sizeof(m));
3274 m.tex[0] = R_GetTexture(basetexture);
3275 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3276 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3277 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3278 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3279 if (r_textureunits.integer >= 2)
3282 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3283 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3284 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3285 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3286 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3287 if (r_textureunits.integer >= 3)
3289 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3290 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3291 m.texmatrix[2] = rsurface.entitytoattenuationz;
3292 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3293 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3294 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3297 R_Mesh_TextureState(&m);
3298 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3299 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3302 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3303 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3307 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3308 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3312 extern cvar_t gl_lightmaps;
3313 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)
3315 float ambientscale, diffusescale, specularscale;
3316 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3318 // calculate colors to render this texture with
3319 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3320 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3321 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3322 ambientscale = rsurface.rtlight->ambientscale;
3323 diffusescale = rsurface.rtlight->diffusescale;
3324 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3325 if (!r_shadow_usenormalmap.integer)
3327 ambientscale += 1.0f * diffusescale;
3331 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3333 RSurf_SetupDepthAndCulling();
3334 nmap = rsurface.texture->currentskinframe->nmap;
3335 if (gl_lightmaps.integer)
3336 nmap = r_texture_blanknormalmap;
3337 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3339 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3340 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3343 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3344 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3345 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3348 VectorClear(lightcolorpants);
3351 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3352 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3353 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3356 VectorClear(lightcolorshirt);
3357 switch (r_shadow_rendermode)
3359 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3360 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3361 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
3363 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3364 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);
3366 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3367 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);
3369 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3370 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);
3373 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3379 switch (r_shadow_rendermode)
3381 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3382 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3383 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);
3385 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3386 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);
3388 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3389 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);
3391 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3392 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);
3395 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3401 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)
3403 matrix4x4_t tempmatrix = *matrix;
3404 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3406 // if this light has been compiled before, free the associated data
3407 R_RTLight_Uncompile(rtlight);
3409 // clear it completely to avoid any lingering data
3410 memset(rtlight, 0, sizeof(*rtlight));
3412 // copy the properties
3413 rtlight->matrix_lighttoworld = tempmatrix;
3414 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3415 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3416 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3417 VectorCopy(color, rtlight->color);
3418 rtlight->cubemapname[0] = 0;
3419 if (cubemapname && cubemapname[0])
3420 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3421 rtlight->shadow = shadow;
3422 rtlight->corona = corona;
3423 rtlight->style = style;
3424 rtlight->isstatic = isstatic;
3425 rtlight->coronasizescale = coronasizescale;
3426 rtlight->ambientscale = ambientscale;
3427 rtlight->diffusescale = diffusescale;
3428 rtlight->specularscale = specularscale;
3429 rtlight->flags = flags;
3431 // compute derived data
3432 //rtlight->cullradius = rtlight->radius;
3433 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3434 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3435 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3436 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3437 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3438 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3439 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3442 // compiles rtlight geometry
3443 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3444 void R_RTLight_Compile(rtlight_t *rtlight)
3447 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3448 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3449 entity_render_t *ent = r_refdef.scene.worldentity;
3450 dp_model_t *model = r_refdef.scene.worldmodel;
3451 unsigned char *data;
3454 // compile the light
3455 rtlight->compiled = true;
3456 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3457 rtlight->static_numleafs = 0;
3458 rtlight->static_numleafpvsbytes = 0;
3459 rtlight->static_leaflist = NULL;
3460 rtlight->static_leafpvs = NULL;
3461 rtlight->static_numsurfaces = 0;
3462 rtlight->static_surfacelist = NULL;
3463 rtlight->static_shadowmap_receivers = 0x3F;
3464 rtlight->static_shadowmap_casters = 0x3F;
3465 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3466 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3467 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3468 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3469 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3470 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3472 if (model && model->GetLightInfo)
3474 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3475 r_shadow_compilingrtlight = rtlight;
3476 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);
3477 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);
3478 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3479 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3480 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3481 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3482 rtlight->static_numsurfaces = numsurfaces;
3483 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3484 rtlight->static_numleafs = numleafs;
3485 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3486 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3487 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3488 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3489 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3490 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3491 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3492 if (rtlight->static_numsurfaces)
3493 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3494 if (rtlight->static_numleafs)
3495 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3496 if (rtlight->static_numleafpvsbytes)
3497 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3498 if (rtlight->static_numshadowtrispvsbytes)
3499 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3500 if (rtlight->static_numlighttrispvsbytes)
3501 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3502 switch (rtlight->shadowmode)
3504 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3505 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3506 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3507 if (model->CompileShadowMap && rtlight->shadow)
3508 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3511 if (model->CompileShadowVolume && rtlight->shadow)
3512 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3515 // now we're done compiling the rtlight
3516 r_shadow_compilingrtlight = NULL;
3520 // use smallest available cullradius - box radius or light radius
3521 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3522 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3524 shadowzpasstris = 0;
3525 if (rtlight->static_meshchain_shadow_zpass)
3526 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3527 shadowzpasstris += mesh->numtriangles;
3529 shadowzfailtris = 0;
3530 if (rtlight->static_meshchain_shadow_zfail)
3531 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3532 shadowzfailtris += mesh->numtriangles;
3535 if (rtlight->static_numlighttrispvsbytes)
3536 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3537 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3541 if (rtlight->static_numlighttrispvsbytes)
3542 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3543 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3546 if (developer.integer >= 10)
3547 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);
3550 void R_RTLight_Uncompile(rtlight_t *rtlight)
3552 if (rtlight->compiled)
3554 if (rtlight->static_meshchain_shadow_zpass)
3555 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3556 rtlight->static_meshchain_shadow_zpass = NULL;
3557 if (rtlight->static_meshchain_shadow_zfail)
3558 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3559 rtlight->static_meshchain_shadow_zfail = NULL;
3560 if (rtlight->static_meshchain_shadow_shadowmap)
3561 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3562 rtlight->static_meshchain_shadow_shadowmap = NULL;
3563 // these allocations are grouped
3564 if (rtlight->static_surfacelist)
3565 Mem_Free(rtlight->static_surfacelist);
3566 rtlight->static_numleafs = 0;
3567 rtlight->static_numleafpvsbytes = 0;
3568 rtlight->static_leaflist = NULL;
3569 rtlight->static_leafpvs = NULL;
3570 rtlight->static_numsurfaces = 0;
3571 rtlight->static_surfacelist = NULL;
3572 rtlight->static_numshadowtrispvsbytes = 0;
3573 rtlight->static_shadowtrispvs = NULL;
3574 rtlight->static_numlighttrispvsbytes = 0;
3575 rtlight->static_lighttrispvs = NULL;
3576 rtlight->compiled = false;
3580 void R_Shadow_UncompileWorldLights(void)
3584 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3585 for (lightindex = 0;lightindex < range;lightindex++)
3587 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3590 R_RTLight_Uncompile(&light->rtlight);
3594 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3598 // reset the count of frustum planes
3599 // see rsurface.rtlight_frustumplanes definition for how much this array
3601 rsurface.rtlight_numfrustumplanes = 0;
3603 // haven't implemented a culling path for ortho rendering
3604 if (!r_refdef.view.useperspective)
3606 // check if the light is on screen and copy the 4 planes if it is
3607 for (i = 0;i < 4;i++)
3608 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3611 for (i = 0;i < 4;i++)
3612 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3617 // generate a deformed frustum that includes the light origin, this is
3618 // used to cull shadow casting surfaces that can not possibly cast a
3619 // shadow onto the visible light-receiving surfaces, which can be a
3622 // if the light origin is onscreen the result will be 4 planes exactly
3623 // if the light origin is offscreen on only one axis the result will
3624 // be exactly 5 planes (split-side case)
3625 // if the light origin is offscreen on two axes the result will be
3626 // exactly 4 planes (stretched corner case)
3627 for (i = 0;i < 4;i++)
3629 // quickly reject standard frustum planes that put the light
3630 // origin outside the frustum
3631 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3634 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3636 // if all the standard frustum planes were accepted, the light is onscreen
3637 // otherwise we need to generate some more planes below...
3638 if (rsurface.rtlight_numfrustumplanes < 4)
3640 // at least one of the stock frustum planes failed, so we need to
3641 // create one or two custom planes to enclose the light origin
3642 for (i = 0;i < 4;i++)
3644 // create a plane using the view origin and light origin, and a
3645 // single point from the frustum corner set
3646 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3647 VectorNormalize(plane.normal);
3648 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3649 // see if this plane is backwards and flip it if so
3650 for (j = 0;j < 4;j++)
3651 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3655 VectorNegate(plane.normal, plane.normal);
3657 // flipped plane, test again to see if it is now valid
3658 for (j = 0;j < 4;j++)
3659 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3661 // if the plane is still not valid, then it is dividing the
3662 // frustum and has to be rejected
3666 // we have created a valid plane, compute extra info
3667 PlaneClassify(&plane);
3669 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3671 // if we've found 5 frustum planes then we have constructed a
3672 // proper split-side case and do not need to keep searching for
3673 // planes to enclose the light origin
3674 if (rsurface.rtlight_numfrustumplanes == 5)
3682 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3684 plane = rsurface.rtlight_frustumplanes[i];
3685 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));
3690 // now add the light-space box planes if the light box is rotated, as any
3691 // caster outside the oriented light box is irrelevant (even if it passed
3692 // the worldspace light box, which is axial)
3693 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3695 for (i = 0;i < 6;i++)
3699 v[i >> 1] = (i & 1) ? -1 : 1;
3700 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3701 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3702 plane.dist = VectorNormalizeLength(plane.normal);
3703 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3704 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3710 // add the world-space reduced box planes
3711 for (i = 0;i < 6;i++)
3713 VectorClear(plane.normal);
3714 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3715 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3716 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3725 // reduce all plane distances to tightly fit the rtlight cull box, which
3727 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3728 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3729 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3730 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3731 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3732 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3733 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3734 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3735 oldnum = rsurface.rtlight_numfrustumplanes;
3736 rsurface.rtlight_numfrustumplanes = 0;
3737 for (j = 0;j < oldnum;j++)
3739 // find the nearest point on the box to this plane
3740 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3741 for (i = 1;i < 8;i++)
3743 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3744 if (bestdist > dist)
3747 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);
3748 // if the nearest point is near or behind the plane, we want this
3749 // plane, otherwise the plane is useless as it won't cull anything
3750 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3752 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3753 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3760 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3764 RSurf_ActiveWorldEntity();
3766 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3769 GL_CullFace(GL_NONE);
3770 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3771 for (;mesh;mesh = mesh->next)
3773 if (!mesh->sidetotals[r_shadow_shadowmapside])
3775 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3776 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3777 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3781 else if (r_refdef.scene.worldentity->model)
3782 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3784 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3787 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3792 int surfacelistindex;
3793 msurface_t *surface;
3795 RSurf_ActiveWorldEntity();
3797 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3800 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3801 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3802 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3803 for (;mesh;mesh = mesh->next)
3805 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3806 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3807 GL_LockArrays(0, mesh->numverts);
3808 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3810 // increment stencil if frontface is infront of depthbuffer
3811 GL_CullFace(r_refdef.view.cullface_back);
3812 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3813 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3814 // decrement stencil if backface is infront of depthbuffer
3815 GL_CullFace(r_refdef.view.cullface_front);
3816 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3818 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3820 // decrement stencil if backface is behind depthbuffer
3821 GL_CullFace(r_refdef.view.cullface_front);
3822 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3823 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3824 // increment stencil if frontface is behind depthbuffer
3825 GL_CullFace(r_refdef.view.cullface_back);
3826 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3828 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3829 GL_LockArrays(0, 0);
3833 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3835 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3836 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3838 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3839 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3840 if (CHECKPVSBIT(trispvs, t))
3841 shadowmarklist[numshadowmark++] = t;
3843 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);
3845 else if (numsurfaces)
3846 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3848 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3851 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3853 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3854 vec_t relativeshadowradius;
3855 RSurf_ActiveModelEntity(ent, false, false);
3856 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3857 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3858 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3859 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3860 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3861 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3862 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3863 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3864 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3866 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3869 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3870 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3873 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3875 // set up properties for rendering light onto this entity
3876 RSurf_ActiveModelEntity(ent, true, true);
3877 GL_AlphaTest(false);
3878 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3879 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3880 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3881 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3882 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3883 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3886 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3888 if (!r_refdef.scene.worldmodel->DrawLight)
3891 // set up properties for rendering light onto this entity
3892 RSurf_ActiveWorldEntity();
3893 GL_AlphaTest(false);
3894 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3895 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3896 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3897 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3898 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3899 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3901 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3903 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3906 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3908 dp_model_t *model = ent->model;
3909 if (!model->DrawLight)
3912 R_Shadow_SetupEntityLight(ent);
3914 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3916 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3919 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3923 int numleafs, numsurfaces;
3924 int *leaflist, *surfacelist;
3925 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3926 int numlightentities;
3927 int numlightentities_noselfshadow;
3928 int numshadowentities;
3929 int numshadowentities_noselfshadow;
3930 static entity_render_t *lightentities[MAX_EDICTS];
3931 static entity_render_t *shadowentities[MAX_EDICTS];
3932 static unsigned char entitysides[MAX_EDICTS];
3933 int lightentities_noselfshadow;
3934 int shadowentities_noselfshadow;
3935 vec3_t nearestpoint;
3937 qboolean castshadows;
3940 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3941 // skip lights that are basically invisible (color 0 0 0)
3942 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3945 // loading is done before visibility checks because loading should happen
3946 // all at once at the start of a level, not when it stalls gameplay.
3947 // (especially important to benchmarks)
3949 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3951 if (rtlight->compiled)
3952 R_RTLight_Uncompile(rtlight);
3953 R_RTLight_Compile(rtlight);
3957 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3959 // look up the light style value at this time
3960 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3961 VectorScale(rtlight->color, f, rtlight->currentcolor);
3963 if (rtlight->selected)
3965 f = 2 + sin(realtime * M_PI * 4.0);
3966 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3970 // if lightstyle is currently off, don't draw the light
3971 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3974 // if the light box is offscreen, skip it
3975 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3978 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3979 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3981 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3983 // compiled light, world available and can receive realtime lighting
3984 // retrieve leaf information
3985 numleafs = rtlight->static_numleafs;
3986 leaflist = rtlight->static_leaflist;
3987 leafpvs = rtlight->static_leafpvs;
3988 numsurfaces = rtlight->static_numsurfaces;
3989 surfacelist = rtlight->static_surfacelist;
3990 surfacesides = NULL;
3991 shadowtrispvs = rtlight->static_shadowtrispvs;
3992 lighttrispvs = rtlight->static_lighttrispvs;
3994 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3996 // dynamic light, world available and can receive realtime lighting
3997 // calculate lit surfaces and leafs
3998 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);
3999 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);
4000 leaflist = r_shadow_buffer_leaflist;
4001 leafpvs = r_shadow_buffer_leafpvs;
4002 surfacelist = r_shadow_buffer_surfacelist;
4003 surfacesides = r_shadow_buffer_surfacesides;
4004 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4005 lighttrispvs = r_shadow_buffer_lighttrispvs;
4006 // if the reduced leaf bounds are offscreen, skip it
4007 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4018 surfacesides = NULL;
4019 shadowtrispvs = NULL;
4020 lighttrispvs = NULL;
4022 // check if light is illuminating any visible leafs
4025 for (i = 0;i < numleafs;i++)
4026 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4031 // set up a scissor rectangle for this light
4032 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4035 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4037 // make a list of lit entities and shadow casting entities
4038 numlightentities = 0;
4039 numlightentities_noselfshadow = 0;
4040 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4041 numshadowentities = 0;
4042 numshadowentities_noselfshadow = 0;
4043 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4045 // add dynamic entities that are lit by the light
4046 if (r_drawentities.integer)
4048 for (i = 0;i < r_refdef.scene.numentities;i++)
4051 entity_render_t *ent = r_refdef.scene.entities[i];
4053 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4055 // skip the object entirely if it is not within the valid
4056 // shadow-casting region (which includes the lit region)
4057 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4059 if (!(model = ent->model))
4061 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4063 // this entity wants to receive light, is visible, and is
4064 // inside the light box
4065 // TODO: check if the surfaces in the model can receive light
4066 // so now check if it's in a leaf seen by the light
4067 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))
4069 if (ent->flags & RENDER_NOSELFSHADOW)
4070 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4072 lightentities[numlightentities++] = ent;
4073 // since it is lit, it probably also casts a shadow...
4074 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4075 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4076 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4078 // note: exterior models without the RENDER_NOSELFSHADOW
4079 // flag still create a RENDER_NOSELFSHADOW shadow but
4080 // are lit normally, this means that they are
4081 // self-shadowing but do not shadow other
4082 // RENDER_NOSELFSHADOW entities such as the gun
4083 // (very weird, but keeps the player shadow off the gun)
4084 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4085 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4087 shadowentities[numshadowentities++] = ent;
4090 else if (ent->flags & RENDER_SHADOW)
4092 // this entity is not receiving light, but may still need to
4094 // TODO: check if the surfaces in the model can cast shadow
4095 // now check if it is in a leaf seen by the light
4096 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))
4098 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4099 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4100 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4102 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4103 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4105 shadowentities[numshadowentities++] = ent;
4111 // return if there's nothing at all to light
4112 if (!numlightentities && !numsurfaces)
4115 // don't let sound skip if going slow
4116 if (r_refdef.scene.extraupdate)
4119 // make this the active rtlight for rendering purposes
4120 R_Shadow_RenderMode_ActiveLight(rtlight);
4121 // count this light in the r_speeds
4122 r_refdef.stats.lights++;
4124 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4126 // optionally draw visible shape of the shadow volumes
4127 // for performance analysis by level designers
4128 R_Shadow_RenderMode_VisibleShadowVolumes();
4130 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4131 for (i = 0;i < numshadowentities;i++)
4132 R_Shadow_DrawEntityShadow(shadowentities[i]);
4133 for (i = 0;i < numshadowentities_noselfshadow;i++)
4134 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4137 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4139 // optionally draw the illuminated areas
4140 // for performance analysis by level designers
4141 R_Shadow_RenderMode_VisibleLighting(false, false);
4143 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4144 for (i = 0;i < numlightentities;i++)
4145 R_Shadow_DrawEntityLight(lightentities[i]);
4146 for (i = 0;i < numlightentities_noselfshadow;i++)
4147 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4150 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4152 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4153 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4154 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4155 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4156 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4157 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4159 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4165 int receivermask = 0;
4166 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4167 Matrix4x4_Abs(&radiustolight);
4169 r_shadow_shadowmaplod = 0;
4170 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4171 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4172 r_shadow_shadowmaplod = i;
4174 size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4175 size = bound(1, size, 2048);
4176 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4180 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4182 castermask = rtlight->static_shadowmap_casters;
4183 receivermask = rtlight->static_shadowmap_receivers;
4187 for(i = 0;i < numsurfaces;i++)
4189 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4190 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4191 castermask |= surfacesides[i];
4192 receivermask |= surfacesides[i];
4196 if (receivermask < 0x3F)
4198 for (i = 0;i < numlightentities;i++)
4199 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4200 if (receivermask < 0x3F)
4201 for(i = 0; i < numlightentities_noselfshadow;i++)
4202 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4205 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4209 for (i = 0;i < numshadowentities;i++)
4210 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4211 for (i = 0;i < numshadowentities_noselfshadow;i++)
4212 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4215 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4217 // render shadow casters into 6 sided depth texture
4218 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4220 R_Shadow_RenderMode_ShadowMap(side, true, size);
4221 if (! (castermask & (1 << side))) continue;
4223 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4224 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4225 R_Shadow_DrawEntityShadow(shadowentities[i]);
4228 if (numlightentities_noselfshadow)
4230 // render lighting using the depth texture as shadowmap
4231 // draw lighting in the unmasked areas
4232 R_Shadow_RenderMode_Lighting(false, false, true);
4233 for (i = 0;i < numlightentities_noselfshadow;i++)
4234 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4237 // render shadow casters into 6 sided depth texture
4238 if (numshadowentities_noselfshadow)
4240 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4242 R_Shadow_RenderMode_ShadowMap(side, false, size);
4243 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4244 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4248 // render lighting using the depth texture as shadowmap
4249 // draw lighting in the unmasked areas
4250 R_Shadow_RenderMode_Lighting(false, false, true);
4251 // draw lighting in the unmasked areas
4253 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4254 for (i = 0;i < numlightentities;i++)
4255 R_Shadow_DrawEntityLight(lightentities[i]);
4257 else if (castshadows && gl_stencil)
4259 // draw stencil shadow volumes to mask off pixels that are in shadow
4260 // so that they won't receive lighting
4261 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4262 R_Shadow_ClearStencil();
4264 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4265 for (i = 0;i < numshadowentities;i++)
4266 R_Shadow_DrawEntityShadow(shadowentities[i]);
4267 if (numlightentities_noselfshadow)
4269 // draw lighting in the unmasked areas
4270 R_Shadow_RenderMode_Lighting(true, false, false);
4271 for (i = 0;i < numlightentities_noselfshadow;i++)
4272 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4274 // optionally draw the illuminated areas
4275 // for performance analysis by level designers
4276 if (r_showlighting.integer && r_refdef.view.showdebug)
4278 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4279 for (i = 0;i < numlightentities_noselfshadow;i++)
4280 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4283 for (i = 0;i < numshadowentities_noselfshadow;i++)
4284 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4286 if (numsurfaces + numlightentities)
4288 // draw lighting in the unmasked areas
4289 R_Shadow_RenderMode_Lighting(true, false, false);
4291 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4292 for (i = 0;i < numlightentities;i++)
4293 R_Shadow_DrawEntityLight(lightentities[i]);
4298 if (numsurfaces + numlightentities)
4300 // draw lighting in the unmasked areas
4301 R_Shadow_RenderMode_Lighting(false, false, false);
4303 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4304 for (i = 0;i < numlightentities;i++)
4305 R_Shadow_DrawEntityLight(lightentities[i]);
4306 for (i = 0;i < numlightentities_noselfshadow;i++)
4307 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4312 void R_Shadow_DrawLightSprites(void);
4313 void R_ShadowVolumeLighting(qboolean visible)
4321 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4322 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) ||
4323 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4324 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4325 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4326 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4327 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4328 R_Shadow_FreeShadowMaps();
4330 if (r_editlights.integer)
4331 R_Shadow_DrawLightSprites();
4333 R_Shadow_RenderMode_Begin();
4335 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4336 if (r_shadow_debuglight.integer >= 0)
4338 lightindex = r_shadow_debuglight.integer;
4339 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4340 if (light && (light->flags & flag))
4341 R_DrawRTLight(&light->rtlight, visible);
4345 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4346 for (lightindex = 0;lightindex < range;lightindex++)
4348 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4349 if (light && (light->flags & flag))
4350 R_DrawRTLight(&light->rtlight, visible);
4353 if (r_refdef.scene.rtdlight)
4354 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4355 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4357 R_Shadow_RenderMode_End();
4360 extern const float r_screenvertex3f[12];
4361 extern void R_SetupView(qboolean allowwaterclippingplane);
4362 extern void R_ResetViewRendering3D(void);
4363 extern void R_ResetViewRendering2D(void);
4364 extern cvar_t r_shadows;
4365 extern cvar_t r_shadows_darken;
4366 extern cvar_t r_shadows_drawafterrtlighting;
4367 extern cvar_t r_shadows_castfrombmodels;
4368 extern cvar_t r_shadows_throwdistance;
4369 extern cvar_t r_shadows_throwdirection;
4370 void R_DrawModelShadows(void)
4373 float relativethrowdistance;
4374 entity_render_t *ent;
4375 vec3_t relativelightorigin;
4376 vec3_t relativelightdirection;
4377 vec3_t relativeshadowmins, relativeshadowmaxs;
4378 vec3_t tmp, shadowdir;
4380 if (!r_drawentities.integer || !gl_stencil)
4384 R_ResetViewRendering3D();
4385 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4386 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4387 R_Shadow_RenderMode_Begin();
4388 R_Shadow_RenderMode_ActiveLight(NULL);
4389 r_shadow_lightscissor[0] = r_refdef.view.x;
4390 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4391 r_shadow_lightscissor[2] = r_refdef.view.width;
4392 r_shadow_lightscissor[3] = r_refdef.view.height;
4393 R_Shadow_RenderMode_StencilShadowVolumes(false);
4396 if (r_shadows.integer == 2)
4398 Math_atov(r_shadows_throwdirection.string, shadowdir);
4399 VectorNormalize(shadowdir);
4402 R_Shadow_ClearStencil();
4404 for (i = 0;i < r_refdef.scene.numentities;i++)
4406 ent = r_refdef.scene.entities[i];
4408 // cast shadows from anything of the map (submodels are optional)
4409 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4411 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4412 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4413 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4414 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4415 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4418 if(ent->entitynumber != 0)
4420 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4421 int entnum, entnum2, recursion;
4422 entnum = entnum2 = ent->entitynumber;
4423 for(recursion = 32; recursion > 0; --recursion)
4425 entnum2 = cl.entities[entnum].state_current.tagentity;
4426 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4431 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4433 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4434 // transform into modelspace of OUR entity
4435 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4436 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4439 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4442 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4445 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4446 RSurf_ActiveModelEntity(ent, false, false);
4447 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4448 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4452 // not really the right mode, but this will disable any silly stencil features
4453 R_Shadow_RenderMode_End();
4455 // set up ortho view for rendering this pass
4456 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4457 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4458 //GL_ScissorTest(true);
4459 //R_Mesh_Matrix(&identitymatrix);
4460 //R_Mesh_ResetTextureState();
4461 R_ResetViewRendering2D();
4462 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4463 R_Mesh_ColorPointer(NULL, 0, 0);
4464 R_SetupGenericShader(false);
4466 // set up a darkening blend on shadowed areas
4467 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4468 //GL_DepthRange(0, 1);
4469 //GL_DepthTest(false);
4470 //GL_DepthMask(false);
4471 //GL_PolygonOffset(0, 0);CHECKGLERROR
4472 GL_Color(0, 0, 0, r_shadows_darken.value);
4473 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4474 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4475 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4476 qglStencilMask(~0);CHECKGLERROR
4477 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4478 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4480 // apply the blend to the shadowed areas
4481 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4483 // restore the viewport
4484 R_SetViewport(&r_refdef.view.viewport);
4486 // restore other state to normal
4487 //R_Shadow_RenderMode_End();
4490 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4493 vec3_t centerorigin;
4494 // if it's too close, skip it
4495 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4497 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4500 if (usequery && r_numqueries + 2 <= r_maxqueries)
4502 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4503 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4504 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4507 // 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
4508 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4509 qglDepthFunc(GL_ALWAYS);
4510 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);
4511 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4512 qglDepthFunc(GL_LEQUAL);
4513 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4514 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);
4515 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4518 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4521 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4524 GLint allpixels = 0, visiblepixels = 0;
4525 // now we have to check the query result
4526 if (rtlight->corona_queryindex_visiblepixels)
4529 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4530 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4532 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4533 if (visiblepixels < 1 || allpixels < 1)
4535 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4536 cscale *= rtlight->corona_visibility;
4540 // FIXME: these traces should scan all render entities instead of cl.world
4541 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4544 VectorScale(rtlight->color, cscale, color);
4545 if (VectorLength(color) > (1.0f / 256.0f))
4546 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);
4549 void R_DrawCoronas(void)
4557 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4559 if (r_waterstate.renderingscene)
4561 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4562 R_Mesh_Matrix(&identitymatrix);
4564 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4566 // check occlusion of coronas
4567 // use GL_ARB_occlusion_query if available
4568 // otherwise use raytraces
4570 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4573 GL_ColorMask(0,0,0,0);
4574 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4575 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4578 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4579 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4581 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4585 for (lightindex = 0;lightindex < range;lightindex++)
4587 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4590 rtlight = &light->rtlight;
4591 rtlight->corona_visibility = 0;
4592 rtlight->corona_queryindex_visiblepixels = 0;
4593 rtlight->corona_queryindex_allpixels = 0;
4594 if (!(rtlight->flags & flag))
4596 if (rtlight->corona <= 0)
4598 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4600 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4602 for (i = 0;i < r_refdef.scene.numlights;i++)
4604 rtlight = r_refdef.scene.lights[i];
4605 rtlight->corona_visibility = 0;
4606 rtlight->corona_queryindex_visiblepixels = 0;
4607 rtlight->corona_queryindex_allpixels = 0;
4608 if (!(rtlight->flags & flag))
4610 if (rtlight->corona <= 0)
4612 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4615 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4617 // now draw the coronas using the query data for intensity info
4618 for (lightindex = 0;lightindex < range;lightindex++)
4620 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4623 rtlight = &light->rtlight;
4624 if (rtlight->corona_visibility <= 0)
4626 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4628 for (i = 0;i < r_refdef.scene.numlights;i++)
4630 rtlight = r_refdef.scene.lights[i];
4631 if (rtlight->corona_visibility <= 0)
4633 if (gl_flashblend.integer)
4634 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4636 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4642 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4643 typedef struct suffixinfo_s
4646 qboolean flipx, flipy, flipdiagonal;
4649 static suffixinfo_t suffix[3][6] =
4652 {"px", false, false, false},
4653 {"nx", false, false, false},
4654 {"py", false, false, false},
4655 {"ny", false, false, false},
4656 {"pz", false, false, false},
4657 {"nz", false, false, false}
4660 {"posx", false, false, false},
4661 {"negx", false, false, false},
4662 {"posy", false, false, false},
4663 {"negy", false, false, false},
4664 {"posz", false, false, false},
4665 {"negz", false, false, false}
4668 {"rt", true, false, true},
4669 {"lf", false, true, true},
4670 {"ft", true, true, false},
4671 {"bk", false, false, false},
4672 {"up", true, false, true},
4673 {"dn", true, false, true}
4677 static int componentorder[4] = {0, 1, 2, 3};
4679 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4681 int i, j, cubemapsize;
4682 unsigned char *cubemappixels, *image_buffer;
4683 rtexture_t *cubemaptexture;
4685 // must start 0 so the first loadimagepixels has no requested width/height
4687 cubemappixels = NULL;
4688 cubemaptexture = NULL;
4689 // keep trying different suffix groups (posx, px, rt) until one loads
4690 for (j = 0;j < 3 && !cubemappixels;j++)
4692 // load the 6 images in the suffix group
4693 for (i = 0;i < 6;i++)
4695 // generate an image name based on the base and and suffix
4696 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4698 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4700 // an image loaded, make sure width and height are equal
4701 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4703 // if this is the first image to load successfully, allocate the cubemap memory
4704 if (!cubemappixels && image_width >= 1)
4706 cubemapsize = image_width;
4707 // note this clears to black, so unavailable sides are black
4708 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4710 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4712 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);
4715 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4717 Mem_Free(image_buffer);
4721 // if a cubemap loaded, upload it
4724 if (developer_loading.integer)
4725 Con_Printf("loading cubemap \"%s\"\n", basename);
4727 if (!r_shadow_filters_texturepool)
4728 r_shadow_filters_texturepool = R_AllocTexturePool();
4729 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4730 Mem_Free(cubemappixels);
4734 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4735 if (developer_loading.integer)
4737 Con_Printf("(tried tried images ");
4738 for (j = 0;j < 3;j++)
4739 for (i = 0;i < 6;i++)
4740 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4741 Con_Print(" and was unable to find any of them).\n");
4744 return cubemaptexture;
4747 rtexture_t *R_Shadow_Cubemap(const char *basename)
4750 for (i = 0;i < numcubemaps;i++)
4751 if (!strcasecmp(cubemaps[i].basename, basename))
4752 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4753 if (i >= MAX_CUBEMAPS)
4754 return r_texture_whitecube;
4756 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4757 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4758 return cubemaps[i].texture;
4761 void R_Shadow_FreeCubemaps(void)
4764 for (i = 0;i < numcubemaps;i++)
4766 if (developer_loading.integer)
4767 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4768 if (cubemaps[i].texture)
4769 R_FreeTexture(cubemaps[i].texture);
4773 R_FreeTexturePool(&r_shadow_filters_texturepool);
4776 dlight_t *R_Shadow_NewWorldLight(void)
4778 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4781 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)
4784 // validate parameters
4785 if (style < 0 || style >= MAX_LIGHTSTYLES)
4787 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4793 // copy to light properties
4794 VectorCopy(origin, light->origin);
4795 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4796 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4797 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4798 light->color[0] = max(color[0], 0);
4799 light->color[1] = max(color[1], 0);
4800 light->color[2] = max(color[2], 0);
4801 light->radius = max(radius, 0);
4802 light->style = style;
4803 light->shadow = shadowenable;
4804 light->corona = corona;
4805 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4806 light->coronasizescale = coronasizescale;
4807 light->ambientscale = ambientscale;
4808 light->diffusescale = diffusescale;
4809 light->specularscale = specularscale;
4810 light->flags = flags;
4812 // update renderable light data
4813 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4814 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);
4817 void R_Shadow_FreeWorldLight(dlight_t *light)
4819 if (r_shadow_selectedlight == light)
4820 r_shadow_selectedlight = NULL;
4821 R_RTLight_Uncompile(&light->rtlight);
4822 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4825 void R_Shadow_ClearWorldLights(void)
4829 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4830 for (lightindex = 0;lightindex < range;lightindex++)
4832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4834 R_Shadow_FreeWorldLight(light);
4836 r_shadow_selectedlight = NULL;
4837 R_Shadow_FreeCubemaps();
4840 void R_Shadow_SelectLight(dlight_t *light)
4842 if (r_shadow_selectedlight)
4843 r_shadow_selectedlight->selected = false;
4844 r_shadow_selectedlight = light;
4845 if (r_shadow_selectedlight)
4846 r_shadow_selectedlight->selected = true;
4849 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4851 // this is never batched (there can be only one)
4852 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);
4855 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4862 // this is never batched (due to the ent parameter changing every time)
4863 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4864 const dlight_t *light = (dlight_t *)ent;
4867 VectorScale(light->color, intensity, spritecolor);
4868 if (VectorLength(spritecolor) < 0.1732f)
4869 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4870 if (VectorLength(spritecolor) > 1.0f)
4871 VectorNormalize(spritecolor);
4873 // draw light sprite
4874 if (light->cubemapname[0] && !light->shadow)
4875 pic = r_editlights_sprcubemapnoshadowlight;
4876 else if (light->cubemapname[0])
4877 pic = r_editlights_sprcubemaplight;
4878 else if (!light->shadow)
4879 pic = r_editlights_sprnoshadowlight;
4881 pic = r_editlights_sprlight;
4882 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);
4883 // draw selection sprite if light is selected
4884 if (light->selected)
4885 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);
4886 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4889 void R_Shadow_DrawLightSprites(void)
4893 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4894 for (lightindex = 0;lightindex < range;lightindex++)
4896 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4898 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4900 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4903 void R_Shadow_SelectLightInView(void)
4905 float bestrating, rating, temp[3];
4909 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4912 for (lightindex = 0;lightindex < range;lightindex++)
4914 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4917 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4918 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4921 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4922 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4924 bestrating = rating;
4929 R_Shadow_SelectLight(best);
4932 void R_Shadow_LoadWorldLights(void)
4934 int n, a, style, shadow, flags;
4935 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4936 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4937 if (cl.worldmodel == NULL)
4939 Con_Print("No map loaded.\n");
4942 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4943 strlcat (name, ".rtlights", sizeof (name));
4944 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4954 for (;COM_Parse(t, true) && strcmp(
4955 if (COM_Parse(t, true))
4957 if (com_token[0] == '!')
4960 origin[0] = atof(com_token+1);
4963 origin[0] = atof(com_token);
4968 while (*s && *s != '\n' && *s != '\r')
4974 // check for modifier flags
4981 #if _MSC_VER >= 1400
4982 #define sscanf sscanf_s
4984 cubemapname[sizeof(cubemapname)-1] = 0;
4985 #if MAX_QPATH != 128
4986 #error update this code if MAX_QPATH changes
4988 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
4989 #if _MSC_VER >= 1400
4990 , sizeof(cubemapname)
4992 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4995 flags = LIGHTFLAG_REALTIMEMODE;
5003 coronasizescale = 0.25f;
5005 VectorClear(angles);
5008 if (a < 9 || !strcmp(cubemapname, "\"\""))
5010 // remove quotes on cubemapname
5011 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5014 namelen = strlen(cubemapname) - 2;
5015 memmove(cubemapname, cubemapname + 1, namelen);
5016 cubemapname[namelen] = '\0';
5020 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);
5023 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5031 Con_Printf("invalid rtlights file \"%s\"\n", name);
5032 Mem_Free(lightsstring);
5036 void R_Shadow_SaveWorldLights(void)
5040 size_t bufchars, bufmaxchars;
5042 char name[MAX_QPATH];
5043 char line[MAX_INPUTLINE];
5044 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5045 // I hate lines which are 3 times my screen size :( --blub
5048 if (cl.worldmodel == NULL)
5050 Con_Print("No map loaded.\n");
5053 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5054 strlcat (name, ".rtlights", sizeof (name));
5055 bufchars = bufmaxchars = 0;
5057 for (lightindex = 0;lightindex < range;lightindex++)
5059 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5062 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5063 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);
5064 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5065 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]);
5067 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);
5068 if (bufchars + strlen(line) > bufmaxchars)
5070 bufmaxchars = bufchars + strlen(line) + 2048;
5072 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5076 memcpy(buf, oldbuf, bufchars);
5082 memcpy(buf + bufchars, line, strlen(line));
5083 bufchars += strlen(line);
5087 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5092 void R_Shadow_LoadLightsFile(void)
5095 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5096 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5097 if (cl.worldmodel == NULL)
5099 Con_Print("No map loaded.\n");
5102 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5103 strlcat (name, ".lights", sizeof (name));
5104 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5112 while (*s && *s != '\n' && *s != '\r')
5118 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);
5122 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);
5125 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5126 radius = bound(15, radius, 4096);
5127 VectorScale(color, (2.0f / (8388608.0f)), color);
5128 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5136 Con_Printf("invalid lights file \"%s\"\n", name);
5137 Mem_Free(lightsstring);
5141 // tyrlite/hmap2 light types in the delay field
5142 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5144 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5146 int entnum, style, islight, skin, pflags, effects, type, n;
5149 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5150 char key[256], value[MAX_INPUTLINE];
5152 if (cl.worldmodel == NULL)
5154 Con_Print("No map loaded.\n");
5157 // try to load a .ent file first
5158 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5159 strlcat (key, ".ent", sizeof (key));
5160 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5161 // and if that is not found, fall back to the bsp file entity string
5163 data = cl.worldmodel->brush.entities;
5166 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5168 type = LIGHTTYPE_MINUSX;
5169 origin[0] = origin[1] = origin[2] = 0;
5170 originhack[0] = originhack[1] = originhack[2] = 0;
5171 angles[0] = angles[1] = angles[2] = 0;
5172 color[0] = color[1] = color[2] = 1;
5173 light[0] = light[1] = light[2] = 1;light[3] = 300;
5174 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5184 if (!COM_ParseToken_Simple(&data, false, false))
5186 if (com_token[0] == '}')
5187 break; // end of entity
5188 if (com_token[0] == '_')
5189 strlcpy(key, com_token + 1, sizeof(key));
5191 strlcpy(key, com_token, sizeof(key));
5192 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5193 key[strlen(key)-1] = 0;
5194 if (!COM_ParseToken_Simple(&data, false, false))
5196 strlcpy(value, com_token, sizeof(value));
5198 // now that we have the key pair worked out...
5199 if (!strcmp("light", key))
5201 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5205 light[0] = vec[0] * (1.0f / 256.0f);
5206 light[1] = vec[0] * (1.0f / 256.0f);
5207 light[2] = vec[0] * (1.0f / 256.0f);
5213 light[0] = vec[0] * (1.0f / 255.0f);
5214 light[1] = vec[1] * (1.0f / 255.0f);
5215 light[2] = vec[2] * (1.0f / 255.0f);
5219 else if (!strcmp("delay", key))
5221 else if (!strcmp("origin", key))
5222 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5223 else if (!strcmp("angle", key))
5224 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5225 else if (!strcmp("angles", key))
5226 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5227 else if (!strcmp("color", key))
5228 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5229 else if (!strcmp("wait", key))
5230 fadescale = atof(value);
5231 else if (!strcmp("classname", key))
5233 if (!strncmp(value, "light", 5))
5236 if (!strcmp(value, "light_fluoro"))
5241 overridecolor[0] = 1;
5242 overridecolor[1] = 1;
5243 overridecolor[2] = 1;
5245 if (!strcmp(value, "light_fluorospark"))
5250 overridecolor[0] = 1;
5251 overridecolor[1] = 1;
5252 overridecolor[2] = 1;
5254 if (!strcmp(value, "light_globe"))
5259 overridecolor[0] = 1;
5260 overridecolor[1] = 0.8;
5261 overridecolor[2] = 0.4;
5263 if (!strcmp(value, "light_flame_large_yellow"))
5268 overridecolor[0] = 1;
5269 overridecolor[1] = 0.5;
5270 overridecolor[2] = 0.1;
5272 if (!strcmp(value, "light_flame_small_yellow"))
5277 overridecolor[0] = 1;
5278 overridecolor[1] = 0.5;
5279 overridecolor[2] = 0.1;
5281 if (!strcmp(value, "light_torch_small_white"))
5286 overridecolor[0] = 1;
5287 overridecolor[1] = 0.5;
5288 overridecolor[2] = 0.1;
5290 if (!strcmp(value, "light_torch_small_walltorch"))
5295 overridecolor[0] = 1;
5296 overridecolor[1] = 0.5;
5297 overridecolor[2] = 0.1;
5301 else if (!strcmp("style", key))
5302 style = atoi(value);
5303 else if (!strcmp("skin", key))
5304 skin = (int)atof(value);
5305 else if (!strcmp("pflags", key))
5306 pflags = (int)atof(value);
5307 else if (!strcmp("effects", key))
5308 effects = (int)atof(value);
5309 else if (cl.worldmodel->type == mod_brushq3)
5311 if (!strcmp("scale", key))
5312 lightscale = atof(value);
5313 if (!strcmp("fade", key))
5314 fadescale = atof(value);
5319 if (lightscale <= 0)
5323 if (color[0] == color[1] && color[0] == color[2])
5325 color[0] *= overridecolor[0];
5326 color[1] *= overridecolor[1];
5327 color[2] *= overridecolor[2];
5329 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5330 color[0] = color[0] * light[0];
5331 color[1] = color[1] * light[1];
5332 color[2] = color[2] * light[2];
5335 case LIGHTTYPE_MINUSX:
5337 case LIGHTTYPE_RECIPX:
5339 VectorScale(color, (1.0f / 16.0f), color);
5341 case LIGHTTYPE_RECIPXX:
5343 VectorScale(color, (1.0f / 16.0f), color);
5346 case LIGHTTYPE_NONE:
5350 case LIGHTTYPE_MINUSXX:
5353 VectorAdd(origin, originhack, origin);
5355 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);
5358 Mem_Free(entfiledata);
5362 void R_Shadow_SetCursorLocationForView(void)
5365 vec3_t dest, endpos;
5367 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5368 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5369 if (trace.fraction < 1)
5371 dist = trace.fraction * r_editlights_cursordistance.value;
5372 push = r_editlights_cursorpushback.value;
5376 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5377 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5381 VectorClear( endpos );
5383 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5384 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5385 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5388 void R_Shadow_UpdateWorldLightSelection(void)
5390 if (r_editlights.integer)
5392 R_Shadow_SetCursorLocationForView();
5393 R_Shadow_SelectLightInView();
5396 R_Shadow_SelectLight(NULL);
5399 void R_Shadow_EditLights_Clear_f(void)
5401 R_Shadow_ClearWorldLights();
5404 void R_Shadow_EditLights_Reload_f(void)
5408 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5409 R_Shadow_ClearWorldLights();
5410 R_Shadow_LoadWorldLights();
5411 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5413 R_Shadow_LoadLightsFile();
5414 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5415 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5419 void R_Shadow_EditLights_Save_f(void)
5423 R_Shadow_SaveWorldLights();
5426 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5428 R_Shadow_ClearWorldLights();
5429 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5432 void R_Shadow_EditLights_ImportLightsFile_f(void)
5434 R_Shadow_ClearWorldLights();
5435 R_Shadow_LoadLightsFile();
5438 void R_Shadow_EditLights_Spawn_f(void)
5441 if (!r_editlights.integer)
5443 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5446 if (Cmd_Argc() != 1)
5448 Con_Print("r_editlights_spawn does not take parameters\n");
5451 color[0] = color[1] = color[2] = 1;
5452 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5455 void R_Shadow_EditLights_Edit_f(void)
5457 vec3_t origin, angles, color;
5458 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5459 int style, shadows, flags, normalmode, realtimemode;
5460 char cubemapname[MAX_INPUTLINE];
5461 if (!r_editlights.integer)
5463 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5466 if (!r_shadow_selectedlight)
5468 Con_Print("No selected light.\n");
5471 VectorCopy(r_shadow_selectedlight->origin, origin);
5472 VectorCopy(r_shadow_selectedlight->angles, angles);
5473 VectorCopy(r_shadow_selectedlight->color, color);
5474 radius = r_shadow_selectedlight->radius;
5475 style = r_shadow_selectedlight->style;
5476 if (r_shadow_selectedlight->cubemapname)
5477 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5480 shadows = r_shadow_selectedlight->shadow;
5481 corona = r_shadow_selectedlight->corona;
5482 coronasizescale = r_shadow_selectedlight->coronasizescale;
5483 ambientscale = r_shadow_selectedlight->ambientscale;
5484 diffusescale = r_shadow_selectedlight->diffusescale;
5485 specularscale = r_shadow_selectedlight->specularscale;
5486 flags = r_shadow_selectedlight->flags;
5487 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5488 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5489 if (!strcmp(Cmd_Argv(1), "origin"))
5491 if (Cmd_Argc() != 5)
5493 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5496 origin[0] = atof(Cmd_Argv(2));
5497 origin[1] = atof(Cmd_Argv(3));
5498 origin[2] = atof(Cmd_Argv(4));
5500 else if (!strcmp(Cmd_Argv(1), "originx"))
5502 if (Cmd_Argc() != 3)
5504 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5507 origin[0] = atof(Cmd_Argv(2));
5509 else if (!strcmp(Cmd_Argv(1), "originy"))
5511 if (Cmd_Argc() != 3)
5513 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5516 origin[1] = atof(Cmd_Argv(2));
5518 else if (!strcmp(Cmd_Argv(1), "originz"))
5520 if (Cmd_Argc() != 3)
5522 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5525 origin[2] = atof(Cmd_Argv(2));
5527 else if (!strcmp(Cmd_Argv(1), "move"))
5529 if (Cmd_Argc() != 5)
5531 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5534 origin[0] += atof(Cmd_Argv(2));
5535 origin[1] += atof(Cmd_Argv(3));
5536 origin[2] += atof(Cmd_Argv(4));
5538 else if (!strcmp(Cmd_Argv(1), "movex"))
5540 if (Cmd_Argc() != 3)
5542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5545 origin[0] += atof(Cmd_Argv(2));
5547 else if (!strcmp(Cmd_Argv(1), "movey"))
5549 if (Cmd_Argc() != 3)
5551 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5554 origin[1] += atof(Cmd_Argv(2));
5556 else if (!strcmp(Cmd_Argv(1), "movez"))
5558 if (Cmd_Argc() != 3)
5560 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5563 origin[2] += atof(Cmd_Argv(2));
5565 else if (!strcmp(Cmd_Argv(1), "angles"))
5567 if (Cmd_Argc() != 5)
5569 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5572 angles[0] = atof(Cmd_Argv(2));
5573 angles[1] = atof(Cmd_Argv(3));
5574 angles[2] = atof(Cmd_Argv(4));
5576 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5578 if (Cmd_Argc() != 3)
5580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5583 angles[0] = atof(Cmd_Argv(2));
5585 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5587 if (Cmd_Argc() != 3)
5589 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5592 angles[1] = atof(Cmd_Argv(2));
5594 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5596 if (Cmd_Argc() != 3)
5598 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5601 angles[2] = atof(Cmd_Argv(2));
5603 else if (!strcmp(Cmd_Argv(1), "color"))
5605 if (Cmd_Argc() != 5)
5607 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5610 color[0] = atof(Cmd_Argv(2));
5611 color[1] = atof(Cmd_Argv(3));
5612 color[2] = atof(Cmd_Argv(4));
5614 else if (!strcmp(Cmd_Argv(1), "radius"))
5616 if (Cmd_Argc() != 3)
5618 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5621 radius = atof(Cmd_Argv(2));
5623 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5625 if (Cmd_Argc() == 3)
5627 double scale = atof(Cmd_Argv(2));
5634 if (Cmd_Argc() != 5)
5636 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5639 color[0] *= atof(Cmd_Argv(2));
5640 color[1] *= atof(Cmd_Argv(3));
5641 color[2] *= atof(Cmd_Argv(4));
5644 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5646 if (Cmd_Argc() != 3)
5648 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5651 radius *= atof(Cmd_Argv(2));
5653 else if (!strcmp(Cmd_Argv(1), "style"))
5655 if (Cmd_Argc() != 3)
5657 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5660 style = atoi(Cmd_Argv(2));
5662 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5666 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5669 if (Cmd_Argc() == 3)
5670 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5674 else if (!strcmp(Cmd_Argv(1), "shadows"))
5676 if (Cmd_Argc() != 3)
5678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5681 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5683 else if (!strcmp(Cmd_Argv(1), "corona"))
5685 if (Cmd_Argc() != 3)
5687 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5690 corona = atof(Cmd_Argv(2));
5692 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5694 if (Cmd_Argc() != 3)
5696 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5699 coronasizescale = atof(Cmd_Argv(2));
5701 else if (!strcmp(Cmd_Argv(1), "ambient"))
5703 if (Cmd_Argc() != 3)
5705 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5708 ambientscale = atof(Cmd_Argv(2));
5710 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5712 if (Cmd_Argc() != 3)
5714 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5717 diffusescale = atof(Cmd_Argv(2));
5719 else if (!strcmp(Cmd_Argv(1), "specular"))
5721 if (Cmd_Argc() != 3)
5723 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5726 specularscale = atof(Cmd_Argv(2));
5728 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5730 if (Cmd_Argc() != 3)
5732 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5735 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5737 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5739 if (Cmd_Argc() != 3)
5741 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5744 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5748 Con_Print("usage: r_editlights_edit [property] [value]\n");
5749 Con_Print("Selected light's properties:\n");
5750 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5751 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5752 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5753 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5754 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5755 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5756 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5757 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5758 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5759 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5760 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5761 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5762 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5763 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5766 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5767 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5770 void R_Shadow_EditLights_EditAll_f(void)
5776 if (!r_editlights.integer)
5778 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5782 // EditLights doesn't seem to have a "remove" command or something so:
5783 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5784 for (lightindex = 0;lightindex < range;lightindex++)
5786 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5789 R_Shadow_SelectLight(light);
5790 R_Shadow_EditLights_Edit_f();
5794 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5796 int lightnumber, lightcount;
5797 size_t lightindex, range;
5801 if (!r_editlights.integer)
5803 x = vid_conwidth.value - 240;
5805 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5808 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5809 for (lightindex = 0;lightindex < range;lightindex++)
5811 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5814 if (light == r_shadow_selectedlight)
5815 lightnumber = lightindex;
5818 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;
5819 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;
5821 if (r_shadow_selectedlight == NULL)
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5834 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;
5835 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;
5836 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;
5837 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;
5840 void R_Shadow_EditLights_ToggleShadow_f(void)
5842 if (!r_editlights.integer)
5844 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5847 if (!r_shadow_selectedlight)
5849 Con_Print("No selected light.\n");
5852 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);
5855 void R_Shadow_EditLights_ToggleCorona_f(void)
5857 if (!r_editlights.integer)
5859 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5862 if (!r_shadow_selectedlight)
5864 Con_Print("No selected light.\n");
5867 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);
5870 void R_Shadow_EditLights_Remove_f(void)
5872 if (!r_editlights.integer)
5874 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5877 if (!r_shadow_selectedlight)
5879 Con_Print("No selected light.\n");
5882 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5883 r_shadow_selectedlight = NULL;
5886 void R_Shadow_EditLights_Help_f(void)
5889 "Documentation on r_editlights system:\n"
5891 "r_editlights : enable/disable editing mode\n"
5892 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5893 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5894 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5895 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5896 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5898 "r_editlights_help : this help\n"
5899 "r_editlights_clear : remove all lights\n"
5900 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5901 "r_editlights_save : save to .rtlights file\n"
5902 "r_editlights_spawn : create a light with default settings\n"
5903 "r_editlights_edit command : edit selected light - more documentation below\n"
5904 "r_editlights_remove : remove selected light\n"
5905 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5906 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5907 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5909 "origin x y z : set light location\n"
5910 "originx x: set x component of light location\n"
5911 "originy y: set y component of light location\n"
5912 "originz z: set z component of light location\n"
5913 "move x y z : adjust light location\n"
5914 "movex x: adjust x component of light location\n"
5915 "movey y: adjust y component of light location\n"
5916 "movez z: adjust z component of light location\n"
5917 "angles x y z : set light angles\n"
5918 "anglesx x: set x component of light angles\n"
5919 "anglesy y: set y component of light angles\n"
5920 "anglesz z: set z component of light angles\n"
5921 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5922 "radius radius : set radius (size) of light\n"
5923 "colorscale grey : multiply color of light (1 does nothing)\n"
5924 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5925 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5926 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5927 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5928 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5929 "shadows 1/0 : turn on/off shadows\n"
5930 "corona n : set corona intensity\n"
5931 "coronasize n : set corona size (0-1)\n"
5932 "ambient n : set ambient intensity (0-1)\n"
5933 "diffuse n : set diffuse intensity (0-1)\n"
5934 "specular n : set specular intensity (0-1)\n"
5935 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5936 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5937 "<nothing> : print light properties to console\n"
5941 void R_Shadow_EditLights_CopyInfo_f(void)
5943 if (!r_editlights.integer)
5945 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5948 if (!r_shadow_selectedlight)
5950 Con_Print("No selected light.\n");
5953 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5954 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5955 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5956 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5957 if (r_shadow_selectedlight->cubemapname)
5958 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5960 r_shadow_bufferlight.cubemapname[0] = 0;
5961 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5962 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5963 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5964 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5965 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5966 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5967 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5970 void R_Shadow_EditLights_PasteInfo_f(void)
5972 if (!r_editlights.integer)
5974 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5977 if (!r_shadow_selectedlight)
5979 Con_Print("No selected light.\n");
5982 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);
5985 void R_Shadow_EditLights_Init(void)
5987 Cvar_RegisterVariable(&r_editlights);
5988 Cvar_RegisterVariable(&r_editlights_cursordistance);
5989 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5990 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5991 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5992 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5993 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5994 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5995 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)");
5996 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5997 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5998 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5999 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)");
6000 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6001 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6002 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6003 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6004 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6005 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6006 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)");
6012 =============================================================================
6016 =============================================================================
6019 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6021 VectorClear(diffusecolor);
6022 VectorClear(diffusenormal);
6024 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6026 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6027 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6030 VectorSet(ambientcolor, 1, 1, 1);
6037 for (i = 0;i < r_refdef.scene.numlights;i++)
6039 light = r_refdef.scene.lights[i];
6040 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6041 f = 1 - VectorLength2(v);
6042 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6043 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);