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_shadowmapdepthbits;
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_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"};
264 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
265 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)"};
266 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"};
267 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
268 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
269 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
270 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
271 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
274 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
275 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
276 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
277 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)"};
278 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
279 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
280 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
281 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
282 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)"};
283 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"};
284 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
285 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
286 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"};
287 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
288 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
289 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)"};
290 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"};
291 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
292 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)"};
293 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
294 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
295 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
298 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
299 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
300 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
301 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
302 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
303 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
304 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
305 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
306 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
307 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)"};
308 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)"};
309 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
310 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"};
311 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
312 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
313 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
314 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
315 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
316 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
317 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
318 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
319 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
320 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
322 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
323 #define ATTENTABLESIZE 256
324 // 1D gradient, 2D circle and 3D sphere attenuation textures
325 #define ATTEN1DSIZE 32
326 #define ATTEN2DSIZE 64
327 #define ATTEN3DSIZE 32
329 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
330 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
331 static float r_shadow_attentable[ATTENTABLESIZE+1];
333 rtlight_t *r_shadow_compilingrtlight;
334 static memexpandablearray_t r_shadow_worldlightsarray;
335 dlight_t *r_shadow_selectedlight;
336 dlight_t r_shadow_bufferlight;
337 vec3_t r_editlights_cursorlocation;
339 extern int con_vislines;
341 typedef struct cubemapinfo_s
348 #define MAX_CUBEMAPS 256
349 static int numcubemaps;
350 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
362 // VorteX: custom editor light sprites
363 #define EDLIGHTSPRSIZE 8
364 cachepic_t *r_editlights_sprcursor;
365 cachepic_t *r_editlights_sprlight;
366 cachepic_t *r_editlights_sprnoshadowlight;
367 cachepic_t *r_editlights_sprcubemaplight;
368 cachepic_t *r_editlights_sprcubemapnoshadowlight;
369 cachepic_t *r_editlights_sprselection;
371 void R_Shadow_SetShadowMode(void)
373 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
374 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
375 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
376 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
377 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
378 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
379 r_shadow_shadowmaplod = -1;
380 r_shadow_shadowmapsize = 0;
381 r_shadow_shadowmapsampler = false;
382 r_shadow_shadowmappcf = 0;
383 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
384 if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
386 if(r_shadow_shadowmapfilterquality < 0)
388 if(strstr(gl_vendor, "NVIDIA"))
390 r_shadow_shadowmapsampler = gl_support_arb_shadow;
391 r_shadow_shadowmappcf = 1;
393 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
394 r_shadow_shadowmappcf = 1;
395 else if(strstr(gl_vendor, "ATI"))
396 r_shadow_shadowmappcf = 1;
398 r_shadow_shadowmapsampler = gl_support_arb_shadow;
402 switch (r_shadow_shadowmapfilterquality)
405 r_shadow_shadowmapsampler = gl_support_arb_shadow;
408 r_shadow_shadowmapsampler = gl_support_arb_shadow;
409 r_shadow_shadowmappcf = 1;
412 r_shadow_shadowmappcf = 1;
415 r_shadow_shadowmappcf = 2;
419 switch (r_shadow_shadowmaptexturetype)
422 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
425 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
428 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
431 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
432 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
433 else if(gl_texturerectangle)
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
442 void R_Shadow_FreeShadowMaps(void)
446 R_Shadow_SetShadowMode();
448 if (r_shadow_fborectangle)
449 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
450 r_shadow_fborectangle = 0;
454 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
457 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
458 if (r_shadow_fbocubeside[i])
459 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
460 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
463 if (r_shadow_shadowmaprectangletexture)
464 R_FreeTexture(r_shadow_shadowmaprectangletexture);
465 r_shadow_shadowmaprectangletexture = NULL;
467 if (r_shadow_shadowmap2dtexture)
468 R_FreeTexture(r_shadow_shadowmap2dtexture);
469 r_shadow_shadowmap2dtexture = NULL;
471 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
472 if (r_shadow_shadowmapcubetexture[i])
473 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
474 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
476 if (r_shadow_shadowmapvsdcttexture)
477 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
478 r_shadow_shadowmapvsdcttexture = NULL;
483 void r_shadow_start(void)
485 // allocate vertex processing arrays
487 r_shadow_attenuationgradienttexture = NULL;
488 r_shadow_attenuation2dtexture = NULL;
489 r_shadow_attenuation3dtexture = NULL;
490 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
491 r_shadow_shadowmaprectangletexture = NULL;
492 r_shadow_shadowmap2dtexture = NULL;
493 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
494 r_shadow_shadowmapvsdcttexture = NULL;
495 r_shadow_shadowmapmaxsize = 0;
496 r_shadow_shadowmapsize = 0;
497 r_shadow_shadowmaplod = 0;
498 r_shadow_shadowmapfilterquality = -1;
499 r_shadow_shadowmaptexturetype = -1;
500 r_shadow_shadowmapdepthbits = 0;
501 r_shadow_shadowmapvsdct = false;
502 r_shadow_shadowmapsampler = false;
503 r_shadow_shadowmappcf = 0;
504 r_shadow_fborectangle = 0;
506 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
508 R_Shadow_FreeShadowMaps();
510 r_shadow_texturepool = NULL;
511 r_shadow_filters_texturepool = NULL;
512 R_Shadow_ValidateCvars();
513 R_Shadow_MakeTextures();
514 maxshadowtriangles = 0;
515 shadowelements = NULL;
516 maxshadowvertices = 0;
517 shadowvertex3f = NULL;
525 shadowmarklist = NULL;
530 shadowsideslist = NULL;
531 r_shadow_buffer_numleafpvsbytes = 0;
532 r_shadow_buffer_visitingleafpvs = NULL;
533 r_shadow_buffer_leafpvs = NULL;
534 r_shadow_buffer_leaflist = NULL;
535 r_shadow_buffer_numsurfacepvsbytes = 0;
536 r_shadow_buffer_surfacepvs = NULL;
537 r_shadow_buffer_surfacelist = NULL;
538 r_shadow_buffer_surfacesides = NULL;
539 r_shadow_buffer_numshadowtrispvsbytes = 0;
540 r_shadow_buffer_shadowtrispvs = NULL;
541 r_shadow_buffer_numlighttrispvsbytes = 0;
542 r_shadow_buffer_lighttrispvs = NULL;
545 void r_shadow_shutdown(void)
548 R_Shadow_UncompileWorldLights();
550 R_Shadow_FreeShadowMaps();
554 r_shadow_attenuationgradienttexture = NULL;
555 r_shadow_attenuation2dtexture = NULL;
556 r_shadow_attenuation3dtexture = NULL;
557 R_FreeTexturePool(&r_shadow_texturepool);
558 R_FreeTexturePool(&r_shadow_filters_texturepool);
559 maxshadowtriangles = 0;
561 Mem_Free(shadowelements);
562 shadowelements = NULL;
564 Mem_Free(shadowvertex3f);
565 shadowvertex3f = NULL;
568 Mem_Free(vertexupdate);
571 Mem_Free(vertexremap);
577 Mem_Free(shadowmark);
580 Mem_Free(shadowmarklist);
581 shadowmarklist = NULL;
586 Mem_Free(shadowsides);
589 Mem_Free(shadowsideslist);
590 shadowsideslist = NULL;
591 r_shadow_buffer_numleafpvsbytes = 0;
592 if (r_shadow_buffer_visitingleafpvs)
593 Mem_Free(r_shadow_buffer_visitingleafpvs);
594 r_shadow_buffer_visitingleafpvs = NULL;
595 if (r_shadow_buffer_leafpvs)
596 Mem_Free(r_shadow_buffer_leafpvs);
597 r_shadow_buffer_leafpvs = NULL;
598 if (r_shadow_buffer_leaflist)
599 Mem_Free(r_shadow_buffer_leaflist);
600 r_shadow_buffer_leaflist = NULL;
601 r_shadow_buffer_numsurfacepvsbytes = 0;
602 if (r_shadow_buffer_surfacepvs)
603 Mem_Free(r_shadow_buffer_surfacepvs);
604 r_shadow_buffer_surfacepvs = NULL;
605 if (r_shadow_buffer_surfacelist)
606 Mem_Free(r_shadow_buffer_surfacelist);
607 r_shadow_buffer_surfacelist = NULL;
608 if (r_shadow_buffer_surfacesides)
609 Mem_Free(r_shadow_buffer_surfacesides);
610 r_shadow_buffer_surfacesides = NULL;
611 r_shadow_buffer_numshadowtrispvsbytes = 0;
612 if (r_shadow_buffer_shadowtrispvs)
613 Mem_Free(r_shadow_buffer_shadowtrispvs);
614 r_shadow_buffer_numlighttrispvsbytes = 0;
615 if (r_shadow_buffer_lighttrispvs)
616 Mem_Free(r_shadow_buffer_lighttrispvs);
619 void r_shadow_newmap(void)
621 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
622 R_Shadow_EditLights_Reload_f();
625 void R_Shadow_Help_f(void)
628 "Documentation on r_shadow system:\n"
630 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
631 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
632 "r_shadow_debuglight : render only this light number (-1 = all)\n"
633 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
634 "r_shadow_gloss2intensity : brightness of forced gloss\n"
635 "r_shadow_glossintensity : brightness of textured gloss\n"
636 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
637 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
638 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
639 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
640 "r_shadow_portallight : use portal visibility for static light precomputation\n"
641 "r_shadow_projectdistance : shadow volume projection distance\n"
642 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
643 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
644 "r_shadow_realtime_world : use high quality world lighting mode\n"
645 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
646 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
647 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
648 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
649 "r_shadow_scissor : use scissor optimization\n"
650 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
651 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
652 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
653 "r_showlighting : useful for performance testing; bright = slow!\n"
654 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
656 "r_shadow_help : this help\n"
660 void R_Shadow_Init(void)
662 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
663 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
664 Cvar_RegisterVariable(&r_shadow_dot3);
665 Cvar_RegisterVariable(&r_shadow_usenormalmap);
666 Cvar_RegisterVariable(&r_shadow_debuglight);
667 Cvar_RegisterVariable(&r_shadow_gloss);
668 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
669 Cvar_RegisterVariable(&r_shadow_glossintensity);
670 Cvar_RegisterVariable(&r_shadow_glossexponent);
671 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
672 Cvar_RegisterVariable(&r_shadow_glossexact);
673 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
674 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
675 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
676 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
677 Cvar_RegisterVariable(&r_shadow_portallight);
678 Cvar_RegisterVariable(&r_shadow_projectdistance);
679 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
680 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
681 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
682 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
683 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
684 Cvar_RegisterVariable(&r_shadow_realtime_world);
685 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
686 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
687 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
688 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
689 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
691 Cvar_RegisterVariable(&r_shadow_scissor);
692 Cvar_RegisterVariable(&r_shadow_shadowmapping);
693 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
694 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
695 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
700 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
701 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
707 Cvar_RegisterVariable(&r_shadow_culltriangles);
708 Cvar_RegisterVariable(&r_shadow_polygonfactor);
709 Cvar_RegisterVariable(&r_shadow_polygonoffset);
710 Cvar_RegisterVariable(&r_shadow_texture3d);
711 Cvar_RegisterVariable(&r_coronas);
712 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
713 Cvar_RegisterVariable(&r_coronas_occlusionquery);
714 Cvar_RegisterVariable(&gl_flashblend);
715 Cvar_RegisterVariable(&gl_ext_separatestencil);
716 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
717 if (gamemode == GAME_TENEBRAE)
719 Cvar_SetValue("r_shadow_gloss", 2);
720 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
722 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
723 R_Shadow_EditLights_Init();
724 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
725 maxshadowtriangles = 0;
726 shadowelements = NULL;
727 maxshadowvertices = 0;
728 shadowvertex3f = NULL;
736 shadowmarklist = NULL;
741 shadowsideslist = NULL;
742 r_shadow_buffer_numleafpvsbytes = 0;
743 r_shadow_buffer_visitingleafpvs = NULL;
744 r_shadow_buffer_leafpvs = NULL;
745 r_shadow_buffer_leaflist = NULL;
746 r_shadow_buffer_numsurfacepvsbytes = 0;
747 r_shadow_buffer_surfacepvs = NULL;
748 r_shadow_buffer_surfacelist = NULL;
749 r_shadow_buffer_surfacesides = NULL;
750 r_shadow_buffer_shadowtrispvs = NULL;
751 r_shadow_buffer_lighttrispvs = NULL;
752 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
755 matrix4x4_t matrix_attenuationxyz =
758 {0.5, 0.0, 0.0, 0.5},
759 {0.0, 0.5, 0.0, 0.5},
760 {0.0, 0.0, 0.5, 0.5},
765 matrix4x4_t matrix_attenuationz =
768 {0.0, 0.0, 0.5, 0.5},
769 {0.0, 0.0, 0.0, 0.5},
770 {0.0, 0.0, 0.0, 0.5},
775 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
777 numvertices = ((numvertices + 255) & ~255) * vertscale;
778 numtriangles = ((numtriangles + 255) & ~255) * triscale;
779 // make sure shadowelements is big enough for this volume
780 if (maxshadowtriangles < numtriangles)
782 maxshadowtriangles = numtriangles;
784 Mem_Free(shadowelements);
785 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
787 // make sure shadowvertex3f is big enough for this volume
788 if (maxshadowvertices < numvertices)
790 maxshadowvertices = numvertices;
792 Mem_Free(shadowvertex3f);
793 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
797 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
799 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
800 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
801 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
802 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
803 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
805 if (r_shadow_buffer_visitingleafpvs)
806 Mem_Free(r_shadow_buffer_visitingleafpvs);
807 if (r_shadow_buffer_leafpvs)
808 Mem_Free(r_shadow_buffer_leafpvs);
809 if (r_shadow_buffer_leaflist)
810 Mem_Free(r_shadow_buffer_leaflist);
811 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
812 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
813 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
814 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
816 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
818 if (r_shadow_buffer_surfacepvs)
819 Mem_Free(r_shadow_buffer_surfacepvs);
820 if (r_shadow_buffer_surfacelist)
821 Mem_Free(r_shadow_buffer_surfacelist);
822 if (r_shadow_buffer_surfacesides)
823 Mem_Free(r_shadow_buffer_surfacesides);
824 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
825 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
826 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
827 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
829 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
831 if (r_shadow_buffer_shadowtrispvs)
832 Mem_Free(r_shadow_buffer_shadowtrispvs);
833 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
834 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
836 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
838 if (r_shadow_buffer_lighttrispvs)
839 Mem_Free(r_shadow_buffer_lighttrispvs);
840 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
841 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
845 void R_Shadow_PrepareShadowMark(int numtris)
847 // make sure shadowmark is big enough for this volume
848 if (maxshadowmark < numtris)
850 maxshadowmark = numtris;
852 Mem_Free(shadowmark);
854 Mem_Free(shadowmarklist);
855 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
856 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
860 // if shadowmarkcount wrapped we clear the array and adjust accordingly
861 if (shadowmarkcount == 0)
864 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
869 void R_Shadow_PrepareShadowSides(int numtris)
871 if (maxshadowsides < numtris)
873 maxshadowsides = numtris;
875 Mem_Free(shadowsides);
877 Mem_Free(shadowsideslist);
878 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
879 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
884 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)
887 int outtriangles = 0, outvertices = 0;
890 float ratio, direction[3], projectvector[3];
892 if (projectdirection)
893 VectorScale(projectdirection, projectdistance, projectvector);
895 VectorClear(projectvector);
897 // create the vertices
898 if (projectdirection)
900 for (i = 0;i < numshadowmarktris;i++)
902 element = inelement3i + shadowmarktris[i] * 3;
903 for (j = 0;j < 3;j++)
905 if (vertexupdate[element[j]] != vertexupdatenum)
907 vertexupdate[element[j]] = vertexupdatenum;
908 vertexremap[element[j]] = outvertices;
909 vertex = invertex3f + element[j] * 3;
910 // project one copy of the vertex according to projectvector
911 VectorCopy(vertex, outvertex3f);
912 VectorAdd(vertex, projectvector, (outvertex3f + 3));
921 for (i = 0;i < numshadowmarktris;i++)
923 element = inelement3i + shadowmarktris[i] * 3;
924 for (j = 0;j < 3;j++)
926 if (vertexupdate[element[j]] != vertexupdatenum)
928 vertexupdate[element[j]] = vertexupdatenum;
929 vertexremap[element[j]] = outvertices;
930 vertex = invertex3f + element[j] * 3;
931 // project one copy of the vertex to the sphere radius of the light
932 // (FIXME: would projecting it to the light box be better?)
933 VectorSubtract(vertex, projectorigin, direction);
934 ratio = projectdistance / VectorLength(direction);
935 VectorCopy(vertex, outvertex3f);
936 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
944 if (r_shadow_frontsidecasting.integer)
946 for (i = 0;i < numshadowmarktris;i++)
948 int remappedelement[3];
950 const int *neighbortriangle;
952 markindex = shadowmarktris[i] * 3;
953 element = inelement3i + markindex;
954 neighbortriangle = inneighbor3i + markindex;
955 // output the front and back triangles
956 outelement3i[0] = vertexremap[element[0]];
957 outelement3i[1] = vertexremap[element[1]];
958 outelement3i[2] = vertexremap[element[2]];
959 outelement3i[3] = vertexremap[element[2]] + 1;
960 outelement3i[4] = vertexremap[element[1]] + 1;
961 outelement3i[5] = vertexremap[element[0]] + 1;
965 // output the sides (facing outward from this triangle)
966 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
968 remappedelement[0] = vertexremap[element[0]];
969 remappedelement[1] = vertexremap[element[1]];
970 outelement3i[0] = remappedelement[1];
971 outelement3i[1] = remappedelement[0];
972 outelement3i[2] = remappedelement[0] + 1;
973 outelement3i[3] = remappedelement[1];
974 outelement3i[4] = remappedelement[0] + 1;
975 outelement3i[5] = remappedelement[1] + 1;
980 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
982 remappedelement[1] = vertexremap[element[1]];
983 remappedelement[2] = vertexremap[element[2]];
984 outelement3i[0] = remappedelement[2];
985 outelement3i[1] = remappedelement[1];
986 outelement3i[2] = remappedelement[1] + 1;
987 outelement3i[3] = remappedelement[2];
988 outelement3i[4] = remappedelement[1] + 1;
989 outelement3i[5] = remappedelement[2] + 1;
994 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[2] = vertexremap[element[2]];
998 outelement3i[0] = remappedelement[0];
999 outelement3i[1] = remappedelement[2];
1000 outelement3i[2] = remappedelement[2] + 1;
1001 outelement3i[3] = remappedelement[0];
1002 outelement3i[4] = remappedelement[2] + 1;
1003 outelement3i[5] = remappedelement[0] + 1;
1012 for (i = 0;i < numshadowmarktris;i++)
1014 int remappedelement[3];
1016 const int *neighbortriangle;
1018 markindex = shadowmarktris[i] * 3;
1019 element = inelement3i + markindex;
1020 neighbortriangle = inneighbor3i + markindex;
1021 // output the front and back triangles
1022 outelement3i[0] = vertexremap[element[2]];
1023 outelement3i[1] = vertexremap[element[1]];
1024 outelement3i[2] = vertexremap[element[0]];
1025 outelement3i[3] = vertexremap[element[0]] + 1;
1026 outelement3i[4] = vertexremap[element[1]] + 1;
1027 outelement3i[5] = vertexremap[element[2]] + 1;
1031 // output the sides (facing outward from this triangle)
1032 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1034 remappedelement[0] = vertexremap[element[0]];
1035 remappedelement[1] = vertexremap[element[1]];
1036 outelement3i[0] = remappedelement[0];
1037 outelement3i[1] = remappedelement[1];
1038 outelement3i[2] = remappedelement[1] + 1;
1039 outelement3i[3] = remappedelement[0];
1040 outelement3i[4] = remappedelement[1] + 1;
1041 outelement3i[5] = remappedelement[0] + 1;
1046 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1048 remappedelement[1] = vertexremap[element[1]];
1049 remappedelement[2] = vertexremap[element[2]];
1050 outelement3i[0] = remappedelement[1];
1051 outelement3i[1] = remappedelement[2];
1052 outelement3i[2] = remappedelement[2] + 1;
1053 outelement3i[3] = remappedelement[1];
1054 outelement3i[4] = remappedelement[2] + 1;
1055 outelement3i[5] = remappedelement[1] + 1;
1060 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1062 remappedelement[0] = vertexremap[element[0]];
1063 remappedelement[2] = vertexremap[element[2]];
1064 outelement3i[0] = remappedelement[2];
1065 outelement3i[1] = remappedelement[0];
1066 outelement3i[2] = remappedelement[0] + 1;
1067 outelement3i[3] = remappedelement[2];
1068 outelement3i[4] = remappedelement[0] + 1;
1069 outelement3i[5] = remappedelement[2] + 1;
1077 *outnumvertices = outvertices;
1078 return outtriangles;
1081 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)
1084 int outtriangles = 0, outvertices = 0;
1086 const float *vertex;
1087 float ratio, direction[3], projectvector[3];
1090 if (projectdirection)
1091 VectorScale(projectdirection, projectdistance, projectvector);
1093 VectorClear(projectvector);
1095 for (i = 0;i < numshadowmarktris;i++)
1097 int remappedelement[3];
1099 const int *neighbortriangle;
1101 markindex = shadowmarktris[i] * 3;
1102 neighbortriangle = inneighbor3i + markindex;
1103 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1104 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1105 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1106 if (side[0] + side[1] + side[2] == 0)
1110 element = inelement3i + markindex;
1112 // create the vertices
1113 for (j = 0;j < 3;j++)
1115 if (side[j] + side[j+1] == 0)
1118 if (vertexupdate[k] != vertexupdatenum)
1120 vertexupdate[k] = vertexupdatenum;
1121 vertexremap[k] = outvertices;
1122 vertex = invertex3f + k * 3;
1123 VectorCopy(vertex, outvertex3f);
1124 if (projectdirection)
1126 // project one copy of the vertex according to projectvector
1127 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1131 // project one copy of the vertex to the sphere radius of the light
1132 // (FIXME: would projecting it to the light box be better?)
1133 VectorSubtract(vertex, projectorigin, direction);
1134 ratio = projectdistance / VectorLength(direction);
1135 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1142 // output the sides (facing outward from this triangle)
1145 remappedelement[0] = vertexremap[element[0]];
1146 remappedelement[1] = vertexremap[element[1]];
1147 outelement3i[0] = remappedelement[1];
1148 outelement3i[1] = remappedelement[0];
1149 outelement3i[2] = remappedelement[0] + 1;
1150 outelement3i[3] = remappedelement[1];
1151 outelement3i[4] = remappedelement[0] + 1;
1152 outelement3i[5] = remappedelement[1] + 1;
1159 remappedelement[1] = vertexremap[element[1]];
1160 remappedelement[2] = vertexremap[element[2]];
1161 outelement3i[0] = remappedelement[2];
1162 outelement3i[1] = remappedelement[1];
1163 outelement3i[2] = remappedelement[1] + 1;
1164 outelement3i[3] = remappedelement[2];
1165 outelement3i[4] = remappedelement[1] + 1;
1166 outelement3i[5] = remappedelement[2] + 1;
1173 remappedelement[0] = vertexremap[element[0]];
1174 remappedelement[2] = vertexremap[element[2]];
1175 outelement3i[0] = remappedelement[0];
1176 outelement3i[1] = remappedelement[2];
1177 outelement3i[2] = remappedelement[2] + 1;
1178 outelement3i[3] = remappedelement[0];
1179 outelement3i[4] = remappedelement[2] + 1;
1180 outelement3i[5] = remappedelement[0] + 1;
1187 *outnumvertices = outvertices;
1188 return outtriangles;
1191 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)
1197 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1199 tend = firsttriangle + numtris;
1200 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1202 // surface box entirely inside light box, no box cull
1203 if (projectdirection)
1205 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1207 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1208 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1209 shadowmarklist[numshadowmark++] = t;
1214 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1215 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1216 shadowmarklist[numshadowmark++] = t;
1221 // surface box not entirely inside light box, cull each triangle
1222 if (projectdirection)
1224 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1226 v[0] = invertex3f + e[0] * 3;
1227 v[1] = invertex3f + e[1] * 3;
1228 v[2] = invertex3f + e[2] * 3;
1229 TriangleNormal(v[0], v[1], v[2], normal);
1230 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1231 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1232 shadowmarklist[numshadowmark++] = t;
1237 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1239 v[0] = invertex3f + e[0] * 3;
1240 v[1] = invertex3f + e[1] * 3;
1241 v[2] = invertex3f + e[2] * 3;
1242 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1243 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1244 shadowmarklist[numshadowmark++] = t;
1250 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1255 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1257 // check if the shadow volume intersects the near plane
1259 // a ray between the eye and light origin may intersect the caster,
1260 // indicating that the shadow may touch the eye location, however we must
1261 // test the near plane (a polygon), not merely the eye location, so it is
1262 // easiest to enlarge the caster bounding shape slightly for this.
1268 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)
1270 int i, tris, outverts;
1271 if (projectdistance < 0.1)
1273 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1276 if (!numverts || !nummarktris)
1278 // make sure shadowelements is big enough for this volume
1279 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1280 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1282 if (maxvertexupdate < numverts)
1284 maxvertexupdate = numverts;
1286 Mem_Free(vertexupdate);
1288 Mem_Free(vertexremap);
1289 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1290 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1291 vertexupdatenum = 0;
1294 if (vertexupdatenum == 0)
1296 vertexupdatenum = 1;
1297 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1298 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1301 for (i = 0;i < nummarktris;i++)
1302 shadowmark[marktris[i]] = shadowmarkcount;
1304 if (r_shadow_compilingrtlight)
1306 // if we're compiling an rtlight, capture the mesh
1307 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1308 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1309 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1310 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1314 // decide which type of shadow to generate and set stencil mode
1315 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1316 // generate the sides or a solid volume, depending on type
1317 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1318 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1320 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1321 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1322 r_refdef.stats.lights_shadowtriangles += tris;
1324 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1325 GL_LockArrays(0, outverts);
1326 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1328 // increment stencil if frontface is infront of depthbuffer
1329 GL_CullFace(r_refdef.view.cullface_front);
1330 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1331 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1332 // decrement stencil if backface is infront of depthbuffer
1333 GL_CullFace(r_refdef.view.cullface_back);
1334 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1336 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1338 // decrement stencil if backface is behind depthbuffer
1339 GL_CullFace(r_refdef.view.cullface_front);
1340 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1341 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1342 // increment stencil if frontface is behind depthbuffer
1343 GL_CullFace(r_refdef.view.cullface_back);
1344 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1346 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1347 GL_LockArrays(0, 0);
1352 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1354 // p1, p2, p3 are in the cubemap's local coordinate system
1355 // bias = border/(size - border)
1358 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1359 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1360 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1361 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1363 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1364 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1365 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1366 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1368 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1369 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1370 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1372 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1373 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1374 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1375 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1377 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1378 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1379 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1380 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1382 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1383 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1384 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1386 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1387 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1388 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1389 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1391 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1392 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1393 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1394 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1396 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1397 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1398 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1403 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1405 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1406 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1409 VectorSubtract(maxs, mins, radius);
1410 VectorScale(radius, 0.5f, radius);
1411 VectorAdd(mins, radius, center);
1412 Matrix4x4_Transform(worldtolight, center, lightcenter);
1413 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1414 VectorSubtract(lightcenter, lightradius, pmin);
1415 VectorAdd(lightcenter, lightradius, pmax);
1417 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1418 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1419 if(ap1 > bias*an1 && ap2 > bias*an2)
1421 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1422 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1423 if(an1 > bias*ap1 && an2 > bias*ap2)
1425 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1426 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1428 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1429 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1430 if(ap1 > bias*an1 && ap2 > bias*an2)
1432 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1433 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1434 if(an1 > bias*ap1 && an2 > bias*ap2)
1436 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1437 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1439 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1440 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1441 if(ap1 > bias*an1 && ap2 > bias*an2)
1443 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1444 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1445 if(an1 > bias*ap1 && an2 > bias*ap2)
1447 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1448 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1453 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1455 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1457 // p is in the cubemap's local coordinate system
1458 // bias = border/(size - border)
1459 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1460 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1461 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1463 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1464 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1465 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1466 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1467 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1468 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1472 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1476 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1477 float scale = (size - 2*border)/size, len;
1478 float bias = border / (float)(size - border), dp, dn, ap, an;
1479 // check if cone enclosing side would cross frustum plane
1480 scale = 2 / (scale*scale + 2);
1481 for (i = 0;i < 5;i++)
1483 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1485 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1486 len = scale*VectorLength2(n);
1487 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1488 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1489 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1491 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1493 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1494 len = scale*VectorLength(n);
1495 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1496 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1497 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1499 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1500 // check if frustum corners/origin cross plane sides
1501 for (i = 0;i < 5;i++)
1503 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1504 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1505 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1506 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1507 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1508 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1509 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1510 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1511 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1512 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1514 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1517 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)
1525 int mask, surfacemask = 0;
1526 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1528 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1529 tend = firsttriangle + numtris;
1530 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1532 // surface box entirely inside light box, no box cull
1533 if (projectdirection)
1535 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1537 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1538 TriangleNormal(v[0], v[1], v[2], normal);
1539 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1541 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1542 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1543 surfacemask |= mask;
1546 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;
1547 shadowsides[numshadowsides] = mask;
1548 shadowsideslist[numshadowsides++] = t;
1555 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1557 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1558 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1560 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1561 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1562 surfacemask |= mask;
1565 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1566 shadowsides[numshadowsides] = mask;
1567 shadowsideslist[numshadowsides++] = t;
1575 // surface box not entirely inside light box, cull each triangle
1576 if (projectdirection)
1578 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1580 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1581 TriangleNormal(v[0], v[1], v[2], normal);
1582 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1583 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1585 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1586 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1587 surfacemask |= mask;
1590 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;
1591 shadowsides[numshadowsides] = mask;
1592 shadowsideslist[numshadowsides++] = t;
1599 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1601 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1602 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1603 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1605 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1606 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1607 surfacemask |= mask;
1610 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;
1611 shadowsides[numshadowsides] = mask;
1612 shadowsideslist[numshadowsides++] = t;
1621 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)
1623 int i, j, outtriangles = 0;
1624 int *outelement3i[6];
1625 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1627 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1628 // make sure shadowelements is big enough for this mesh
1629 if (maxshadowtriangles < outtriangles)
1630 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1632 // compute the offset and size of the separate index lists for each cubemap side
1634 for (i = 0;i < 6;i++)
1636 outelement3i[i] = shadowelements + outtriangles * 3;
1637 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1638 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1639 outtriangles += sidetotals[i];
1642 // gather up the (sparse) triangles into separate index lists for each cubemap side
1643 for (i = 0;i < numsidetris;i++)
1645 const int *element = elements + sidetris[i] * 3;
1646 for (j = 0;j < 6;j++)
1648 if (sides[i] & (1 << j))
1650 outelement3i[j][0] = element[0];
1651 outelement3i[j][1] = element[1];
1652 outelement3i[j][2] = element[2];
1653 outelement3i[j] += 3;
1658 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1661 static void R_Shadow_MakeTextures_MakeCorona(void)
1665 unsigned char pixels[32][32][4];
1666 for (y = 0;y < 32;y++)
1668 dy = (y - 15.5f) * (1.0f / 16.0f);
1669 for (x = 0;x < 32;x++)
1671 dx = (x - 15.5f) * (1.0f / 16.0f);
1672 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1673 a = bound(0, a, 255);
1674 pixels[y][x][0] = a;
1675 pixels[y][x][1] = a;
1676 pixels[y][x][2] = a;
1677 pixels[y][x][3] = 255;
1680 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1683 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1685 float dist = sqrt(x*x+y*y+z*z);
1686 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1687 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1688 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1691 static void R_Shadow_MakeTextures(void)
1694 float intensity, dist;
1696 R_FreeTexturePool(&r_shadow_texturepool);
1697 r_shadow_texturepool = R_AllocTexturePool();
1698 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1699 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1700 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1701 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1702 for (x = 0;x <= ATTENTABLESIZE;x++)
1704 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1705 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1706 r_shadow_attentable[x] = bound(0, intensity, 1);
1708 // 1D gradient texture
1709 for (x = 0;x < ATTEN1DSIZE;x++)
1710 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1711 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);
1712 // 2D circle texture
1713 for (y = 0;y < ATTEN2DSIZE;y++)
1714 for (x = 0;x < ATTEN2DSIZE;x++)
1715 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);
1716 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);
1717 // 3D sphere texture
1718 if (r_shadow_texture3d.integer && gl_texture3d)
1720 for (z = 0;z < ATTEN3DSIZE;z++)
1721 for (y = 0;y < ATTEN3DSIZE;y++)
1722 for (x = 0;x < ATTEN3DSIZE;x++)
1723 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));
1724 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);
1727 r_shadow_attenuation3dtexture = NULL;
1730 R_Shadow_MakeTextures_MakeCorona();
1732 // Editor light sprites
1733 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1734 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1735 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1736 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1737 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1738 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1741 void R_Shadow_ValidateCvars(void)
1743 if (r_shadow_texture3d.integer && !gl_texture3d)
1744 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1745 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1746 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1747 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1748 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1751 void R_Shadow_RenderMode_Begin(void)
1757 R_Shadow_ValidateCvars();
1759 if (!r_shadow_attenuation2dtexture
1760 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1761 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1762 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1763 R_Shadow_MakeTextures();
1766 R_Mesh_ColorPointer(NULL, 0, 0);
1767 R_Mesh_ResetTextureState();
1768 GL_BlendFunc(GL_ONE, GL_ZERO);
1769 GL_DepthRange(0, 1);
1770 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1772 GL_DepthMask(false);
1773 GL_Color(0, 0, 0, 1);
1774 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1776 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1778 if (gl_ext_separatestencil.integer)
1780 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1781 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1783 else if (gl_ext_stenciltwoside.integer)
1785 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1786 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1790 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1791 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1794 if (r_glsl.integer && gl_support_fragment_shader)
1795 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1796 else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil)
1797 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1799 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1803 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1804 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1805 r_shadow_drawbuffer = drawbuffer;
1806 r_shadow_readbuffer = readbuffer;
1808 r_shadow_cullface_front = r_refdef.view.cullface_front;
1809 r_shadow_cullface_back = r_refdef.view.cullface_back;
1812 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1814 rsurface.rtlight = rtlight;
1817 void R_Shadow_RenderMode_Reset(void)
1820 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1822 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1824 if (gl_support_ext_framebuffer_object)
1826 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1829 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1830 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1832 R_SetViewport(&r_refdef.view.viewport);
1833 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1834 R_Mesh_ColorPointer(NULL, 0, 0);
1835 R_Mesh_ResetTextureState();
1836 GL_DepthRange(0, 1);
1838 GL_DepthMask(false);
1839 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1840 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1841 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1842 qglStencilMask(~0);CHECKGLERROR
1843 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1844 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1845 r_refdef.view.cullface_front = r_shadow_cullface_front;
1846 r_refdef.view.cullface_back = r_shadow_cullface_back;
1847 GL_CullFace(r_refdef.view.cullface_back);
1848 GL_Color(1, 1, 1, 1);
1849 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1850 GL_BlendFunc(GL_ONE, GL_ZERO);
1851 R_SetupGenericShader(false);
1852 r_shadow_usingshadowmaprect = false;
1853 r_shadow_usingshadowmapcube = false;
1854 r_shadow_usingshadowmap2d = false;
1858 void R_Shadow_ClearStencil(void)
1861 GL_Clear(GL_STENCIL_BUFFER_BIT);
1862 r_refdef.stats.lights_clears++;
1865 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1867 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1868 if (r_shadow_rendermode == mode)
1871 R_Shadow_RenderMode_Reset();
1872 GL_ColorMask(0, 0, 0, 0);
1873 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1874 R_SetupDepthOrShadowShader();
1875 qglDepthFunc(GL_LESS);CHECKGLERROR
1876 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1877 r_shadow_rendermode = mode;
1882 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1883 GL_CullFace(GL_NONE);
1884 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1885 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1887 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1888 GL_CullFace(GL_NONE);
1889 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1890 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1892 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1893 GL_CullFace(GL_NONE);
1894 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1895 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1896 qglStencilMask(~0);CHECKGLERROR
1897 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1898 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1899 qglStencilMask(~0);CHECKGLERROR
1900 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1902 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1903 GL_CullFace(GL_NONE);
1904 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1905 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1906 qglStencilMask(~0);CHECKGLERROR
1907 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1908 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1909 qglStencilMask(~0);CHECKGLERROR
1910 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1915 static void R_Shadow_MakeVSDCT(void)
1917 // maps to a 2x3 texture rectangle with normalized coordinates
1922 // stores abs(dir.xy), offset.xy/2.5
1923 unsigned char data[4*6] =
1925 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1926 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1927 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1928 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1929 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1930 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1932 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1935 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1939 float nearclip, farclip, bias;
1940 r_viewport_t viewport;
1943 maxsize = r_shadow_shadowmapmaxsize;
1944 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1946 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1947 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1948 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1949 r_shadow_shadowmapside = side;
1950 r_shadow_shadowmapsize = size;
1951 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1953 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1954 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1955 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1956 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1958 // complex unrolled cube approach (more flexible)
1959 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1960 R_Shadow_MakeVSDCT();
1961 if (!r_shadow_shadowmap2dtexture)
1964 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1965 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
1966 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1967 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1968 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1969 // render depth into the fbo, do not render color at all
1970 qglDrawBuffer(GL_NONE);CHECKGLERROR
1971 qglReadBuffer(GL_NONE);CHECKGLERROR
1972 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1973 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1975 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1976 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1981 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1982 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1983 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1984 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1986 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1988 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1989 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1990 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1991 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1993 // complex unrolled cube approach (more flexible)
1994 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1995 R_Shadow_MakeVSDCT();
1996 if (!r_shadow_shadowmaprectangletexture)
1999 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2000 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2001 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2002 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2003 // render depth into the fbo, do not render color at all
2004 qglDrawBuffer(GL_NONE);CHECKGLERROR
2005 qglReadBuffer(GL_NONE);CHECKGLERROR
2006 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2007 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2009 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2010 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2015 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2016 r_shadow_shadowmap_texturescale[0] = 1.0f;
2017 r_shadow_shadowmap_texturescale[1] = 1.0f;
2018 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2020 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2022 r_shadow_shadowmap_parameters[0] = 1.0f;
2023 r_shadow_shadowmap_parameters[1] = 1.0f;
2024 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2025 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2027 // simple cube approach
2028 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2031 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2032 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2033 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2034 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
2035 // render depth into the fbo, do not render color at all
2036 qglDrawBuffer(GL_NONE);CHECKGLERROR
2037 qglReadBuffer(GL_NONE);CHECKGLERROR
2038 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2039 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2041 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2042 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2047 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2048 r_shadow_shadowmap_texturescale[0] = 0.0f;
2049 r_shadow_shadowmap_texturescale[1] = 0.0f;
2050 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2053 R_Shadow_RenderMode_Reset();
2056 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2057 R_SetupDepthOrShadowShader();
2061 R_SetupShowDepthShader();
2062 qglClearColor(1,1,1,1);CHECKGLERROR
2065 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2072 R_SetViewport(&viewport);
2073 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2074 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2076 int flipped = (side&1)^(side>>2);
2077 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2078 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2079 GL_CullFace(r_refdef.view.cullface_back);
2081 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2083 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
2086 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2090 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2094 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2095 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2096 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2097 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2100 R_Shadow_RenderMode_Reset();
2101 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2104 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2108 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2109 // only draw light where this geometry was already rendered AND the
2110 // stencil is 128 (values other than this mean shadow)
2111 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2113 r_shadow_rendermode = r_shadow_lightingrendermode;
2114 // do global setup needed for the chosen lighting mode
2115 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2117 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2118 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2122 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2124 r_shadow_usingshadowmap2d = true;
2125 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2128 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2130 r_shadow_usingshadowmaprect = true;
2131 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2134 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2136 r_shadow_usingshadowmapcube = true;
2137 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2141 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2143 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2148 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2149 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2150 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2154 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2157 R_Shadow_RenderMode_Reset();
2158 GL_BlendFunc(GL_ONE, GL_ONE);
2159 GL_DepthRange(0, 1);
2160 GL_DepthTest(r_showshadowvolumes.integer < 2);
2161 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2162 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2163 GL_CullFace(GL_NONE);
2164 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2167 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2170 R_Shadow_RenderMode_Reset();
2171 GL_BlendFunc(GL_ONE, GL_ONE);
2172 GL_DepthRange(0, 1);
2173 GL_DepthTest(r_showlighting.integer < 2);
2174 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2177 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2181 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2182 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2184 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2187 void R_Shadow_RenderMode_End(void)
2190 R_Shadow_RenderMode_Reset();
2191 R_Shadow_RenderMode_ActiveLight(NULL);
2193 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2194 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2197 int bboxedges[12][2] =
2216 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2218 int i, ix1, iy1, ix2, iy2;
2219 float x1, y1, x2, y2;
2221 float vertex[20][3];
2230 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2231 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2232 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2233 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2235 if (!r_shadow_scissor.integer)
2238 // if view is inside the light box, just say yes it's visible
2239 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2242 x1 = y1 = x2 = y2 = 0;
2244 // transform all corners that are infront of the nearclip plane
2245 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2246 plane4f[3] = r_refdef.view.frustum[4].dist;
2248 for (i = 0;i < 8;i++)
2250 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2251 dist[i] = DotProduct4(corner[i], plane4f);
2252 sign[i] = dist[i] > 0;
2255 VectorCopy(corner[i], vertex[numvertices]);
2259 // if some points are behind the nearclip, add clipped edge points to make
2260 // sure that the scissor boundary is complete
2261 if (numvertices > 0 && numvertices < 8)
2263 // add clipped edge points
2264 for (i = 0;i < 12;i++)
2266 j = bboxedges[i][0];
2267 k = bboxedges[i][1];
2268 if (sign[j] != sign[k])
2270 f = dist[j] / (dist[j] - dist[k]);
2271 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2277 // if we have no points to check, the light is behind the view plane
2281 // if we have some points to transform, check what screen area is covered
2282 x1 = y1 = x2 = y2 = 0;
2284 //Con_Printf("%i vertices to transform...\n", numvertices);
2285 for (i = 0;i < numvertices;i++)
2287 VectorCopy(vertex[i], v);
2288 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2289 //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]);
2292 if (x1 > v2[0]) x1 = v2[0];
2293 if (x2 < v2[0]) x2 = v2[0];
2294 if (y1 > v2[1]) y1 = v2[1];
2295 if (y2 < v2[1]) y2 = v2[1];
2304 // now convert the scissor rectangle to integer screen coordinates
2305 ix1 = (int)(x1 - 1.0f);
2306 iy1 = vid.height - (int)(y2 - 1.0f);
2307 ix2 = (int)(x2 + 1.0f);
2308 iy2 = vid.height - (int)(y1 + 1.0f);
2309 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2311 // clamp it to the screen
2312 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2313 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2314 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2315 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2317 // if it is inside out, it's not visible
2318 if (ix2 <= ix1 || iy2 <= iy1)
2321 // the light area is visible, set up the scissor rectangle
2322 r_shadow_lightscissor[0] = ix1;
2323 r_shadow_lightscissor[1] = iy1;
2324 r_shadow_lightscissor[2] = ix2 - ix1;
2325 r_shadow_lightscissor[3] = iy2 - iy1;
2327 r_refdef.stats.lights_scissored++;
2331 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2333 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2334 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2335 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2336 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2337 if (r_textureunits.integer >= 3)
2339 if (VectorLength2(diffusecolor) > 0)
2341 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2343 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2344 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2345 if ((dot = DotProduct(n, v)) < 0)
2347 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2348 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2351 VectorCopy(ambientcolor, color4f);
2352 if (r_refdef.fogenabled)
2355 f = FogPoint_Model(vertex3f);
2356 VectorScale(color4f, f, color4f);
2363 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2365 VectorCopy(ambientcolor, color4f);
2366 if (r_refdef.fogenabled)
2369 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2370 f = FogPoint_Model(vertex3f);
2371 VectorScale(color4f, f, color4f);
2377 else if (r_textureunits.integer >= 2)
2379 if (VectorLength2(diffusecolor) > 0)
2381 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2383 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2384 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2386 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2387 if ((dot = DotProduct(n, v)) < 0)
2389 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2390 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2391 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2392 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2396 color4f[0] = ambientcolor[0] * distintensity;
2397 color4f[1] = ambientcolor[1] * distintensity;
2398 color4f[2] = ambientcolor[2] * distintensity;
2400 if (r_refdef.fogenabled)
2403 f = FogPoint_Model(vertex3f);
2404 VectorScale(color4f, f, color4f);
2408 VectorClear(color4f);
2414 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2416 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2417 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2419 color4f[0] = ambientcolor[0] * distintensity;
2420 color4f[1] = ambientcolor[1] * distintensity;
2421 color4f[2] = ambientcolor[2] * distintensity;
2422 if (r_refdef.fogenabled)
2425 f = FogPoint_Model(vertex3f);
2426 VectorScale(color4f, f, color4f);
2430 VectorClear(color4f);
2437 if (VectorLength2(diffusecolor) > 0)
2439 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2441 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2442 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2444 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2445 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2446 if ((dot = DotProduct(n, v)) < 0)
2448 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2449 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2450 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2451 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2455 color4f[0] = ambientcolor[0] * distintensity;
2456 color4f[1] = ambientcolor[1] * distintensity;
2457 color4f[2] = ambientcolor[2] * distintensity;
2459 if (r_refdef.fogenabled)
2462 f = FogPoint_Model(vertex3f);
2463 VectorScale(color4f, f, color4f);
2467 VectorClear(color4f);
2473 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2475 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2476 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2478 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2479 color4f[0] = ambientcolor[0] * distintensity;
2480 color4f[1] = ambientcolor[1] * distintensity;
2481 color4f[2] = ambientcolor[2] * distintensity;
2482 if (r_refdef.fogenabled)
2485 f = FogPoint_Model(vertex3f);
2486 VectorScale(color4f, f, color4f);
2490 VectorClear(color4f);
2497 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2499 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2502 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2503 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2504 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2505 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2506 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2508 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2510 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2511 // the cubemap normalizes this for us
2512 out3f[0] = DotProduct(svector3f, lightdir);
2513 out3f[1] = DotProduct(tvector3f, lightdir);
2514 out3f[2] = DotProduct(normal3f, lightdir);
2518 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2521 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2522 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2523 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2524 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2525 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2526 float lightdir[3], eyedir[3], halfdir[3];
2527 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2529 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2530 VectorNormalize(lightdir);
2531 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2532 VectorNormalize(eyedir);
2533 VectorAdd(lightdir, eyedir, halfdir);
2534 // the cubemap normalizes this for us
2535 out3f[0] = DotProduct(svector3f, halfdir);
2536 out3f[1] = DotProduct(tvector3f, halfdir);
2537 out3f[2] = DotProduct(normal3f, halfdir);
2541 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)
2543 // used to display how many times a surface is lit for level design purposes
2544 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2547 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)
2549 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2550 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2551 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2552 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2554 R_Mesh_ColorPointer(NULL, 0, 0);
2555 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2556 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2557 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2558 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2559 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2560 if (rsurface.texture->backgroundcurrentskinframe)
2562 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2563 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2564 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2565 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2567 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2568 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2569 if(rsurface.texture->colormapping)
2571 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2572 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2574 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2575 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2576 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2577 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2578 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2579 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2581 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2583 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2584 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2586 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2590 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)
2592 // shared final code for all the dot3 layers
2594 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2595 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2597 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2598 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2602 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)
2605 // colorscale accounts for how much we multiply the brightness
2608 // mult is how many times the final pass of the lighting will be
2609 // performed to get more brightness than otherwise possible.
2611 // Limit mult to 64 for sanity sake.
2613 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2615 // 3 3D combine path (Geforce3, Radeon 8500)
2616 memset(&m, 0, sizeof(m));
2617 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2618 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2619 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2620 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2621 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2622 m.tex[1] = R_GetTexture(basetexture);
2623 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2624 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2625 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2626 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2627 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2628 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2629 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2630 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2631 m.texmatrix[2] = rsurface.entitytolight;
2632 GL_BlendFunc(GL_ONE, GL_ONE);
2634 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2636 // 2 3D combine path (Geforce3, original Radeon)
2637 memset(&m, 0, sizeof(m));
2638 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2639 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2640 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2641 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2642 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2643 m.tex[1] = R_GetTexture(basetexture);
2644 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2645 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2646 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2647 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2648 GL_BlendFunc(GL_ONE, GL_ONE);
2650 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2652 // 4 2D combine path (Geforce3, Radeon 8500)
2653 memset(&m, 0, sizeof(m));
2654 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2655 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2656 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2658 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2659 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2660 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2661 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2662 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2663 m.texmatrix[1] = rsurface.entitytoattenuationz;
2664 m.tex[2] = R_GetTexture(basetexture);
2665 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2666 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2667 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2668 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2669 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2671 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2672 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2673 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2674 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2675 m.texmatrix[3] = rsurface.entitytolight;
2677 GL_BlendFunc(GL_ONE, GL_ONE);
2679 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2681 // 3 2D combine path (Geforce3, original Radeon)
2682 memset(&m, 0, sizeof(m));
2683 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2684 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2685 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2686 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2687 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2688 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2689 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2690 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2691 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2692 m.texmatrix[1] = rsurface.entitytoattenuationz;
2693 m.tex[2] = R_GetTexture(basetexture);
2694 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2695 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2696 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2697 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2698 GL_BlendFunc(GL_ONE, GL_ONE);
2702 // 2/2/2 2D combine path (any dot3 card)
2703 memset(&m, 0, sizeof(m));
2704 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2705 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2706 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2707 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2708 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2709 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2710 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2711 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2712 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2713 m.texmatrix[1] = rsurface.entitytoattenuationz;
2714 R_Mesh_TextureState(&m);
2715 GL_ColorMask(0,0,0,1);
2716 GL_BlendFunc(GL_ONE, GL_ZERO);
2717 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2720 memset(&m, 0, sizeof(m));
2721 m.tex[0] = R_GetTexture(basetexture);
2722 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2723 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2724 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2725 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2726 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2728 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2729 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2730 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2731 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2732 m.texmatrix[1] = rsurface.entitytolight;
2734 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2736 // this final code is shared
2737 R_Mesh_TextureState(&m);
2738 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);
2741 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)
2744 // colorscale accounts for how much we multiply the brightness
2747 // mult is how many times the final pass of the lighting will be
2748 // performed to get more brightness than otherwise possible.
2750 // Limit mult to 64 for sanity sake.
2752 // generate normalization cubemap texcoords
2753 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2754 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2756 // 3/2 3D combine path (Geforce3, Radeon 8500)
2757 memset(&m, 0, sizeof(m));
2758 m.tex[0] = R_GetTexture(normalmaptexture);
2759 m.texcombinergb[0] = GL_REPLACE;
2760 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2761 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2762 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2763 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2764 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2765 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2766 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2767 m.pointer_texcoord_bufferobject[1] = 0;
2768 m.pointer_texcoord_bufferoffset[1] = 0;
2769 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2770 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2771 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2772 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2773 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2774 R_Mesh_TextureState(&m);
2775 GL_ColorMask(0,0,0,1);
2776 GL_BlendFunc(GL_ONE, GL_ZERO);
2777 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2780 memset(&m, 0, sizeof(m));
2781 m.tex[0] = R_GetTexture(basetexture);
2782 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2783 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2784 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2785 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2786 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2788 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2789 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2790 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2791 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2792 m.texmatrix[1] = rsurface.entitytolight;
2794 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2796 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2798 // 1/2/2 3D combine path (original Radeon)
2799 memset(&m, 0, sizeof(m));
2800 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2801 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2802 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2803 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2804 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2805 R_Mesh_TextureState(&m);
2806 GL_ColorMask(0,0,0,1);
2807 GL_BlendFunc(GL_ONE, GL_ZERO);
2808 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2811 memset(&m, 0, sizeof(m));
2812 m.tex[0] = R_GetTexture(normalmaptexture);
2813 m.texcombinergb[0] = GL_REPLACE;
2814 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2815 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2816 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2817 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2818 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2819 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2820 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2821 m.pointer_texcoord_bufferobject[1] = 0;
2822 m.pointer_texcoord_bufferoffset[1] = 0;
2823 R_Mesh_TextureState(&m);
2824 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2825 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2828 memset(&m, 0, sizeof(m));
2829 m.tex[0] = R_GetTexture(basetexture);
2830 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2831 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2832 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2833 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2834 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2836 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2837 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2838 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2839 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2840 m.texmatrix[1] = rsurface.entitytolight;
2842 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2844 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2846 // 2/2 3D combine path (original Radeon)
2847 memset(&m, 0, sizeof(m));
2848 m.tex[0] = R_GetTexture(normalmaptexture);
2849 m.texcombinergb[0] = GL_REPLACE;
2850 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2851 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2852 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2853 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2854 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2855 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2856 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2857 m.pointer_texcoord_bufferobject[1] = 0;
2858 m.pointer_texcoord_bufferoffset[1] = 0;
2859 R_Mesh_TextureState(&m);
2860 GL_ColorMask(0,0,0,1);
2861 GL_BlendFunc(GL_ONE, GL_ZERO);
2862 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2865 memset(&m, 0, sizeof(m));
2866 m.tex[0] = R_GetTexture(basetexture);
2867 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2868 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2869 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2870 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2871 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2872 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2873 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2874 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2875 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2876 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2878 else if (r_textureunits.integer >= 4)
2880 // 4/2 2D combine path (Geforce3, Radeon 8500)
2881 memset(&m, 0, sizeof(m));
2882 m.tex[0] = R_GetTexture(normalmaptexture);
2883 m.texcombinergb[0] = GL_REPLACE;
2884 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2885 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2886 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2887 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2888 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2889 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2890 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2891 m.pointer_texcoord_bufferobject[1] = 0;
2892 m.pointer_texcoord_bufferoffset[1] = 0;
2893 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2894 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2895 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2896 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2897 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2898 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2899 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2900 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2901 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2902 m.texmatrix[3] = rsurface.entitytoattenuationz;
2903 R_Mesh_TextureState(&m);
2904 GL_ColorMask(0,0,0,1);
2905 GL_BlendFunc(GL_ONE, GL_ZERO);
2906 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2909 memset(&m, 0, sizeof(m));
2910 m.tex[0] = R_GetTexture(basetexture);
2911 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2912 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2913 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2914 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2915 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2917 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2918 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2919 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2920 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2921 m.texmatrix[1] = rsurface.entitytolight;
2923 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2927 // 2/2/2 2D combine path (any dot3 card)
2928 memset(&m, 0, sizeof(m));
2929 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2930 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2931 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2932 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2933 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2934 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2935 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2936 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2937 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2938 m.texmatrix[1] = rsurface.entitytoattenuationz;
2939 R_Mesh_TextureState(&m);
2940 GL_ColorMask(0,0,0,1);
2941 GL_BlendFunc(GL_ONE, GL_ZERO);
2942 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2945 memset(&m, 0, sizeof(m));
2946 m.tex[0] = R_GetTexture(normalmaptexture);
2947 m.texcombinergb[0] = GL_REPLACE;
2948 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2949 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2950 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2951 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2952 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2953 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2954 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2955 m.pointer_texcoord_bufferobject[1] = 0;
2956 m.pointer_texcoord_bufferoffset[1] = 0;
2957 R_Mesh_TextureState(&m);
2958 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2959 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2962 memset(&m, 0, sizeof(m));
2963 m.tex[0] = R_GetTexture(basetexture);
2964 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2965 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2966 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2967 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2968 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2970 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2971 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2972 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2973 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2974 m.texmatrix[1] = rsurface.entitytolight;
2976 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2978 // this final code is shared
2979 R_Mesh_TextureState(&m);
2980 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);
2983 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)
2985 float glossexponent;
2987 // FIXME: detect blendsquare!
2988 //if (!gl_support_blendsquare)
2991 // generate normalization cubemap texcoords
2992 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2993 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2995 // 2/0/0/1/2 3D combine blendsquare path
2996 memset(&m, 0, sizeof(m));
2997 m.tex[0] = R_GetTexture(normalmaptexture);
2998 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2999 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3000 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3001 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3002 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3003 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3004 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3005 m.pointer_texcoord_bufferobject[1] = 0;
3006 m.pointer_texcoord_bufferoffset[1] = 0;
3007 R_Mesh_TextureState(&m);
3008 GL_ColorMask(0,0,0,1);
3009 // this squares the result
3010 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3011 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3013 // second and third pass
3014 R_Mesh_ResetTextureState();
3015 // square alpha in framebuffer a few times to make it shiny
3016 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3017 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3018 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3021 memset(&m, 0, sizeof(m));
3022 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3023 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3024 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3025 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3026 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3027 R_Mesh_TextureState(&m);
3028 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3029 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3032 memset(&m, 0, sizeof(m));
3033 m.tex[0] = R_GetTexture(glosstexture);
3034 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3035 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3036 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3037 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3038 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3040 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3041 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3042 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3043 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3044 m.texmatrix[1] = rsurface.entitytolight;
3046 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3048 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3050 // 2/0/0/2 3D combine blendsquare path
3051 memset(&m, 0, sizeof(m));
3052 m.tex[0] = R_GetTexture(normalmaptexture);
3053 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3054 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3055 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3056 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3057 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3058 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3059 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3060 m.pointer_texcoord_bufferobject[1] = 0;
3061 m.pointer_texcoord_bufferoffset[1] = 0;
3062 R_Mesh_TextureState(&m);
3063 GL_ColorMask(0,0,0,1);
3064 // this squares the result
3065 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3066 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3068 // second and third pass
3069 R_Mesh_ResetTextureState();
3070 // square alpha in framebuffer a few times to make it shiny
3071 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3072 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3073 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3076 memset(&m, 0, sizeof(m));
3077 m.tex[0] = R_GetTexture(glosstexture);
3078 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3079 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3080 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3081 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3082 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3083 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3084 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3085 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3086 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3087 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3091 // 2/0/0/2/2 2D combine blendsquare path
3092 memset(&m, 0, sizeof(m));
3093 m.tex[0] = R_GetTexture(normalmaptexture);
3094 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3095 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3096 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3097 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3098 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3099 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3100 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3101 m.pointer_texcoord_bufferobject[1] = 0;
3102 m.pointer_texcoord_bufferoffset[1] = 0;
3103 R_Mesh_TextureState(&m);
3104 GL_ColorMask(0,0,0,1);
3105 // this squares the result
3106 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3107 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3109 // second and third pass
3110 R_Mesh_ResetTextureState();
3111 // square alpha in framebuffer a few times to make it shiny
3112 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3113 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3114 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3117 memset(&m, 0, sizeof(m));
3118 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3119 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3120 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3121 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3122 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3123 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3124 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3125 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3126 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3127 m.texmatrix[1] = rsurface.entitytoattenuationz;
3128 R_Mesh_TextureState(&m);
3129 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3130 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3133 memset(&m, 0, sizeof(m));
3134 m.tex[0] = R_GetTexture(glosstexture);
3135 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3136 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3137 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3138 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3139 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3141 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3142 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3143 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3144 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3145 m.texmatrix[1] = rsurface.entitytolight;
3147 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3149 // this final code is shared
3150 R_Mesh_TextureState(&m);
3151 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);
3154 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)
3156 // ARB path (any Geforce, any Radeon)
3157 qboolean doambient = ambientscale > 0;
3158 qboolean dodiffuse = diffusescale > 0;
3159 qboolean dospecular = specularscale > 0;
3160 if (!doambient && !dodiffuse && !dospecular)
3162 R_Mesh_ColorPointer(NULL, 0, 0);
3164 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3166 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3170 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3172 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3177 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3179 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3182 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3185 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3192 int newnumtriangles;
3196 int maxtriangles = 4096;
3197 int newelements[4096*3];
3198 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3199 for (renders = 0;renders < 64;renders++)
3204 newnumtriangles = 0;
3206 // due to low fillrate on the cards this vertex lighting path is
3207 // designed for, we manually cull all triangles that do not
3208 // contain a lit vertex
3209 // this builds batches of triangles from multiple surfaces and
3210 // renders them at once
3211 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3213 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3215 if (newnumtriangles)
3217 newfirstvertex = min(newfirstvertex, e[0]);
3218 newlastvertex = max(newlastvertex, e[0]);
3222 newfirstvertex = e[0];
3223 newlastvertex = e[0];
3225 newfirstvertex = min(newfirstvertex, e[1]);
3226 newlastvertex = max(newlastvertex, e[1]);
3227 newfirstvertex = min(newfirstvertex, e[2]);
3228 newlastvertex = max(newlastvertex, e[2]);
3234 if (newnumtriangles >= maxtriangles)
3236 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3237 newnumtriangles = 0;
3243 if (newnumtriangles >= 1)
3245 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3248 // if we couldn't find any lit triangles, exit early
3251 // now reduce the intensity for the next overbright pass
3252 // we have to clamp to 0 here incase the drivers have improper
3253 // handling of negative colors
3254 // (some old drivers even have improper handling of >1 color)
3256 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3258 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3260 c[0] = max(0, c[0] - 1);
3261 c[1] = max(0, c[1] - 1);
3262 c[2] = max(0, c[2] - 1);
3274 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)
3276 // OpenGL 1.1 path (anything)
3277 float ambientcolorbase[3], diffusecolorbase[3];
3278 float ambientcolorpants[3], diffusecolorpants[3];
3279 float ambientcolorshirt[3], diffusecolorshirt[3];
3281 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3282 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3283 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3284 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3285 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3286 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3287 memset(&m, 0, sizeof(m));
3288 m.tex[0] = R_GetTexture(basetexture);
3289 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3290 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3291 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3292 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3293 if (r_textureunits.integer >= 2)
3296 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3297 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3298 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3299 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3300 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3301 if (r_textureunits.integer >= 3)
3303 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3304 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3305 m.texmatrix[2] = rsurface.entitytoattenuationz;
3306 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3307 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3308 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3311 R_Mesh_TextureState(&m);
3312 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3313 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3316 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3317 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3321 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3322 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3326 extern cvar_t gl_lightmaps;
3327 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)
3329 float ambientscale, diffusescale, specularscale;
3330 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3332 // calculate colors to render this texture with
3333 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3334 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3335 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3336 ambientscale = rsurface.rtlight->ambientscale;
3337 diffusescale = rsurface.rtlight->diffusescale;
3338 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3339 if (!r_shadow_usenormalmap.integer)
3341 ambientscale += 1.0f * diffusescale;
3345 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3347 RSurf_SetupDepthAndCulling();
3348 nmap = rsurface.texture->currentskinframe->nmap;
3349 if (gl_lightmaps.integer)
3350 nmap = r_texture_blanknormalmap;
3351 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3353 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3354 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3357 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3358 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3359 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3362 VectorClear(lightcolorpants);
3365 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3366 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3367 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3370 VectorClear(lightcolorshirt);
3371 switch (r_shadow_rendermode)
3373 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3374 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3375 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);
3377 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3378 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);
3380 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3381 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);
3383 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3384 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);
3387 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3393 switch (r_shadow_rendermode)
3395 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3396 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3397 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);
3399 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3400 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);
3402 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3403 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);
3405 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3406 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);
3409 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3415 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)
3417 matrix4x4_t tempmatrix = *matrix;
3418 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3420 // if this light has been compiled before, free the associated data
3421 R_RTLight_Uncompile(rtlight);
3423 // clear it completely to avoid any lingering data
3424 memset(rtlight, 0, sizeof(*rtlight));
3426 // copy the properties
3427 rtlight->matrix_lighttoworld = tempmatrix;
3428 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3429 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3430 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3431 VectorCopy(color, rtlight->color);
3432 rtlight->cubemapname[0] = 0;
3433 if (cubemapname && cubemapname[0])
3434 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3435 rtlight->shadow = shadow;
3436 rtlight->corona = corona;
3437 rtlight->style = style;
3438 rtlight->isstatic = isstatic;
3439 rtlight->coronasizescale = coronasizescale;
3440 rtlight->ambientscale = ambientscale;
3441 rtlight->diffusescale = diffusescale;
3442 rtlight->specularscale = specularscale;
3443 rtlight->flags = flags;
3445 // compute derived data
3446 //rtlight->cullradius = rtlight->radius;
3447 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3448 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3449 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3450 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3451 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3452 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3453 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3456 // compiles rtlight geometry
3457 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3458 void R_RTLight_Compile(rtlight_t *rtlight)
3461 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3462 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3463 entity_render_t *ent = r_refdef.scene.worldentity;
3464 dp_model_t *model = r_refdef.scene.worldmodel;
3465 unsigned char *data;
3468 // compile the light
3469 rtlight->compiled = true;
3470 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3471 rtlight->static_numleafs = 0;
3472 rtlight->static_numleafpvsbytes = 0;
3473 rtlight->static_leaflist = NULL;
3474 rtlight->static_leafpvs = NULL;
3475 rtlight->static_numsurfaces = 0;
3476 rtlight->static_surfacelist = NULL;
3477 rtlight->static_shadowmap_receivers = 0x3F;
3478 rtlight->static_shadowmap_casters = 0x3F;
3479 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3480 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3481 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3482 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3483 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3484 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3486 if (model && model->GetLightInfo)
3488 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3489 r_shadow_compilingrtlight = rtlight;
3490 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);
3491 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);
3492 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3493 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3494 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3495 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3496 rtlight->static_numsurfaces = numsurfaces;
3497 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3498 rtlight->static_numleafs = numleafs;
3499 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3500 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3501 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3502 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3503 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3504 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3505 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3506 if (rtlight->static_numsurfaces)
3507 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3508 if (rtlight->static_numleafs)
3509 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3510 if (rtlight->static_numleafpvsbytes)
3511 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3512 if (rtlight->static_numshadowtrispvsbytes)
3513 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3514 if (rtlight->static_numlighttrispvsbytes)
3515 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3516 switch (rtlight->shadowmode)
3518 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3519 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3520 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3521 if (model->CompileShadowMap && rtlight->shadow)
3522 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3525 if (model->CompileShadowVolume && rtlight->shadow)
3526 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3529 // now we're done compiling the rtlight
3530 r_shadow_compilingrtlight = NULL;
3534 // use smallest available cullradius - box radius or light radius
3535 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3536 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3538 shadowzpasstris = 0;
3539 if (rtlight->static_meshchain_shadow_zpass)
3540 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3541 shadowzpasstris += mesh->numtriangles;
3543 shadowzfailtris = 0;
3544 if (rtlight->static_meshchain_shadow_zfail)
3545 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3546 shadowzfailtris += mesh->numtriangles;
3549 if (rtlight->static_numlighttrispvsbytes)
3550 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3551 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3555 if (rtlight->static_numlighttrispvsbytes)
3556 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3557 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3560 if (developer.integer >= 10)
3561 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);
3564 void R_RTLight_Uncompile(rtlight_t *rtlight)
3566 if (rtlight->compiled)
3568 if (rtlight->static_meshchain_shadow_zpass)
3569 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3570 rtlight->static_meshchain_shadow_zpass = NULL;
3571 if (rtlight->static_meshchain_shadow_zfail)
3572 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3573 rtlight->static_meshchain_shadow_zfail = NULL;
3574 if (rtlight->static_meshchain_shadow_shadowmap)
3575 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3576 rtlight->static_meshchain_shadow_shadowmap = NULL;
3577 // these allocations are grouped
3578 if (rtlight->static_surfacelist)
3579 Mem_Free(rtlight->static_surfacelist);
3580 rtlight->static_numleafs = 0;
3581 rtlight->static_numleafpvsbytes = 0;
3582 rtlight->static_leaflist = NULL;
3583 rtlight->static_leafpvs = NULL;
3584 rtlight->static_numsurfaces = 0;
3585 rtlight->static_surfacelist = NULL;
3586 rtlight->static_numshadowtrispvsbytes = 0;
3587 rtlight->static_shadowtrispvs = NULL;
3588 rtlight->static_numlighttrispvsbytes = 0;
3589 rtlight->static_lighttrispvs = NULL;
3590 rtlight->compiled = false;
3594 void R_Shadow_UncompileWorldLights(void)
3598 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3599 for (lightindex = 0;lightindex < range;lightindex++)
3601 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3604 R_RTLight_Uncompile(&light->rtlight);
3608 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3612 // reset the count of frustum planes
3613 // see rsurface.rtlight_frustumplanes definition for how much this array
3615 rsurface.rtlight_numfrustumplanes = 0;
3617 // haven't implemented a culling path for ortho rendering
3618 if (!r_refdef.view.useperspective)
3620 // check if the light is on screen and copy the 4 planes if it is
3621 for (i = 0;i < 4;i++)
3622 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3625 for (i = 0;i < 4;i++)
3626 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3631 // generate a deformed frustum that includes the light origin, this is
3632 // used to cull shadow casting surfaces that can not possibly cast a
3633 // shadow onto the visible light-receiving surfaces, which can be a
3636 // if the light origin is onscreen the result will be 4 planes exactly
3637 // if the light origin is offscreen on only one axis the result will
3638 // be exactly 5 planes (split-side case)
3639 // if the light origin is offscreen on two axes the result will be
3640 // exactly 4 planes (stretched corner case)
3641 for (i = 0;i < 4;i++)
3643 // quickly reject standard frustum planes that put the light
3644 // origin outside the frustum
3645 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3648 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3650 // if all the standard frustum planes were accepted, the light is onscreen
3651 // otherwise we need to generate some more planes below...
3652 if (rsurface.rtlight_numfrustumplanes < 4)
3654 // at least one of the stock frustum planes failed, so we need to
3655 // create one or two custom planes to enclose the light origin
3656 for (i = 0;i < 4;i++)
3658 // create a plane using the view origin and light origin, and a
3659 // single point from the frustum corner set
3660 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3661 VectorNormalize(plane.normal);
3662 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3663 // see if this plane is backwards and flip it if so
3664 for (j = 0;j < 4;j++)
3665 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3669 VectorNegate(plane.normal, plane.normal);
3671 // flipped plane, test again to see if it is now valid
3672 for (j = 0;j < 4;j++)
3673 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3675 // if the plane is still not valid, then it is dividing the
3676 // frustum and has to be rejected
3680 // we have created a valid plane, compute extra info
3681 PlaneClassify(&plane);
3683 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3685 // if we've found 5 frustum planes then we have constructed a
3686 // proper split-side case and do not need to keep searching for
3687 // planes to enclose the light origin
3688 if (rsurface.rtlight_numfrustumplanes == 5)
3696 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3698 plane = rsurface.rtlight_frustumplanes[i];
3699 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));
3704 // now add the light-space box planes if the light box is rotated, as any
3705 // caster outside the oriented light box is irrelevant (even if it passed
3706 // the worldspace light box, which is axial)
3707 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3709 for (i = 0;i < 6;i++)
3713 v[i >> 1] = (i & 1) ? -1 : 1;
3714 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3715 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3716 plane.dist = VectorNormalizeLength(plane.normal);
3717 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3718 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3724 // add the world-space reduced box planes
3725 for (i = 0;i < 6;i++)
3727 VectorClear(plane.normal);
3728 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3729 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3730 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3739 // reduce all plane distances to tightly fit the rtlight cull box, which
3741 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3742 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3743 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3744 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3745 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3746 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3747 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3748 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3749 oldnum = rsurface.rtlight_numfrustumplanes;
3750 rsurface.rtlight_numfrustumplanes = 0;
3751 for (j = 0;j < oldnum;j++)
3753 // find the nearest point on the box to this plane
3754 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3755 for (i = 1;i < 8;i++)
3757 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3758 if (bestdist > dist)
3761 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);
3762 // if the nearest point is near or behind the plane, we want this
3763 // plane, otherwise the plane is useless as it won't cull anything
3764 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3766 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3767 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3774 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3778 RSurf_ActiveWorldEntity();
3780 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3783 GL_CullFace(GL_NONE);
3784 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3785 for (;mesh;mesh = mesh->next)
3787 if (!mesh->sidetotals[r_shadow_shadowmapside])
3789 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3790 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3791 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3795 else if (r_refdef.scene.worldentity->model)
3796 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);
3798 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3801 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3806 int surfacelistindex;
3807 msurface_t *surface;
3809 RSurf_ActiveWorldEntity();
3811 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3814 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3815 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3816 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3817 for (;mesh;mesh = mesh->next)
3819 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3820 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3821 GL_LockArrays(0, mesh->numverts);
3822 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3824 // increment stencil if frontface is infront of depthbuffer
3825 GL_CullFace(r_refdef.view.cullface_back);
3826 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3827 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3828 // decrement stencil if backface is infront of depthbuffer
3829 GL_CullFace(r_refdef.view.cullface_front);
3830 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3832 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3834 // decrement stencil if backface is behind depthbuffer
3835 GL_CullFace(r_refdef.view.cullface_front);
3836 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3837 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3838 // increment stencil if frontface is behind depthbuffer
3839 GL_CullFace(r_refdef.view.cullface_back);
3840 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3842 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3843 GL_LockArrays(0, 0);
3847 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3849 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3850 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3852 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3853 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3854 if (CHECKPVSBIT(trispvs, t))
3855 shadowmarklist[numshadowmark++] = t;
3857 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);
3859 else if (numsurfaces)
3860 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3862 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3865 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3867 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3868 vec_t relativeshadowradius;
3869 RSurf_ActiveModelEntity(ent, false, false);
3870 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3871 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3872 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3873 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3874 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3875 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3876 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3877 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3878 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3880 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3883 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3884 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3887 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3889 // set up properties for rendering light onto this entity
3890 RSurf_ActiveModelEntity(ent, true, true);
3891 GL_AlphaTest(false);
3892 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3893 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3894 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3895 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3896 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3897 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3900 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3902 if (!r_refdef.scene.worldmodel->DrawLight)
3905 // set up properties for rendering light onto this entity
3906 RSurf_ActiveWorldEntity();
3907 GL_AlphaTest(false);
3908 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3909 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3910 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3911 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3912 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3913 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3915 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3917 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3920 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3922 dp_model_t *model = ent->model;
3923 if (!model->DrawLight)
3926 R_Shadow_SetupEntityLight(ent);
3928 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3930 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3933 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3937 int numleafs, numsurfaces;
3938 int *leaflist, *surfacelist;
3939 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3940 int numlightentities;
3941 int numlightentities_noselfshadow;
3942 int numshadowentities;
3943 int numshadowentities_noselfshadow;
3944 static entity_render_t *lightentities[MAX_EDICTS];
3945 static entity_render_t *shadowentities[MAX_EDICTS];
3946 static unsigned char entitysides[MAX_EDICTS];
3947 int lightentities_noselfshadow;
3948 int shadowentities_noselfshadow;
3949 vec3_t nearestpoint;
3951 qboolean castshadows;
3954 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3955 // skip lights that are basically invisible (color 0 0 0)
3956 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3959 // loading is done before visibility checks because loading should happen
3960 // all at once at the start of a level, not when it stalls gameplay.
3961 // (especially important to benchmarks)
3963 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3965 if (rtlight->compiled)
3966 R_RTLight_Uncompile(rtlight);
3967 R_RTLight_Compile(rtlight);
3971 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3973 // look up the light style value at this time
3974 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3975 VectorScale(rtlight->color, f, rtlight->currentcolor);
3977 if (rtlight->selected)
3979 f = 2 + sin(realtime * M_PI * 4.0);
3980 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3984 // if lightstyle is currently off, don't draw the light
3985 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3988 // if the light box is offscreen, skip it
3989 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3992 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3993 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3995 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3997 // compiled light, world available and can receive realtime lighting
3998 // retrieve leaf information
3999 numleafs = rtlight->static_numleafs;
4000 leaflist = rtlight->static_leaflist;
4001 leafpvs = rtlight->static_leafpvs;
4002 numsurfaces = rtlight->static_numsurfaces;
4003 surfacelist = rtlight->static_surfacelist;
4004 surfacesides = NULL;
4005 shadowtrispvs = rtlight->static_shadowtrispvs;
4006 lighttrispvs = rtlight->static_lighttrispvs;
4008 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4010 // dynamic light, world available and can receive realtime lighting
4011 // calculate lit surfaces and leafs
4012 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);
4013 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);
4014 leaflist = r_shadow_buffer_leaflist;
4015 leafpvs = r_shadow_buffer_leafpvs;
4016 surfacelist = r_shadow_buffer_surfacelist;
4017 surfacesides = r_shadow_buffer_surfacesides;
4018 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4019 lighttrispvs = r_shadow_buffer_lighttrispvs;
4020 // if the reduced leaf bounds are offscreen, skip it
4021 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4032 surfacesides = NULL;
4033 shadowtrispvs = NULL;
4034 lighttrispvs = NULL;
4036 // check if light is illuminating any visible leafs
4039 for (i = 0;i < numleafs;i++)
4040 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4045 // set up a scissor rectangle for this light
4046 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4049 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4051 // make a list of lit entities and shadow casting entities
4052 numlightentities = 0;
4053 numlightentities_noselfshadow = 0;
4054 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4055 numshadowentities = 0;
4056 numshadowentities_noselfshadow = 0;
4057 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4059 // add dynamic entities that are lit by the light
4060 if (r_drawentities.integer)
4062 for (i = 0;i < r_refdef.scene.numentities;i++)
4065 entity_render_t *ent = r_refdef.scene.entities[i];
4067 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4069 // skip the object entirely if it is not within the valid
4070 // shadow-casting region (which includes the lit region)
4071 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4073 if (!(model = ent->model))
4075 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4077 // this entity wants to receive light, is visible, and is
4078 // inside the light box
4079 // TODO: check if the surfaces in the model can receive light
4080 // so now check if it's in a leaf seen by the light
4081 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))
4083 if (ent->flags & RENDER_NOSELFSHADOW)
4084 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4086 lightentities[numlightentities++] = ent;
4087 // since it is lit, it probably also casts a shadow...
4088 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4089 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4090 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4092 // note: exterior models without the RENDER_NOSELFSHADOW
4093 // flag still create a RENDER_NOSELFSHADOW shadow but
4094 // are lit normally, this means that they are
4095 // self-shadowing but do not shadow other
4096 // RENDER_NOSELFSHADOW entities such as the gun
4097 // (very weird, but keeps the player shadow off the gun)
4098 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4099 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4101 shadowentities[numshadowentities++] = ent;
4104 else if (ent->flags & RENDER_SHADOW)
4106 // this entity is not receiving light, but may still need to
4108 // TODO: check if the surfaces in the model can cast shadow
4109 // now check if it is in a leaf seen by the light
4110 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))
4112 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4113 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4114 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4116 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4117 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4119 shadowentities[numshadowentities++] = ent;
4125 // return if there's nothing at all to light
4126 if (!numlightentities && !numsurfaces)
4129 // don't let sound skip if going slow
4130 if (r_refdef.scene.extraupdate)
4133 // make this the active rtlight for rendering purposes
4134 R_Shadow_RenderMode_ActiveLight(rtlight);
4135 // count this light in the r_speeds
4136 r_refdef.stats.lights++;
4138 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4140 // optionally draw visible shape of the shadow volumes
4141 // for performance analysis by level designers
4142 R_Shadow_RenderMode_VisibleShadowVolumes();
4144 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4145 for (i = 0;i < numshadowentities;i++)
4146 R_Shadow_DrawEntityShadow(shadowentities[i]);
4147 for (i = 0;i < numshadowentities_noselfshadow;i++)
4148 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4151 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4153 // optionally draw the illuminated areas
4154 // for performance analysis by level designers
4155 R_Shadow_RenderMode_VisibleLighting(false, false);
4157 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4158 for (i = 0;i < numlightentities;i++)
4159 R_Shadow_DrawEntityLight(lightentities[i]);
4160 for (i = 0;i < numlightentities_noselfshadow;i++)
4161 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4164 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4166 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4167 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4168 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4169 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4171 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4172 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4173 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4175 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4181 int receivermask = 0;
4182 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4183 Matrix4x4_Abs(&radiustolight);
4185 r_shadow_shadowmaplod = 0;
4186 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4187 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4188 r_shadow_shadowmaplod = i;
4190 size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4191 size = bound(1, size, 2048);
4192 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4196 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4198 castermask = rtlight->static_shadowmap_casters;
4199 receivermask = rtlight->static_shadowmap_receivers;
4203 for(i = 0;i < numsurfaces;i++)
4205 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4206 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4207 castermask |= surfacesides[i];
4208 receivermask |= surfacesides[i];
4212 if (receivermask < 0x3F)
4214 for (i = 0;i < numlightentities;i++)
4215 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4216 if (receivermask < 0x3F)
4217 for(i = 0; i < numlightentities_noselfshadow;i++)
4218 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4221 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4225 for (i = 0;i < numshadowentities;i++)
4226 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4227 for (i = 0;i < numshadowentities_noselfshadow;i++)
4228 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4231 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4233 // render shadow casters into 6 sided depth texture
4234 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4236 R_Shadow_RenderMode_ShadowMap(side, true, size);
4237 if (! (castermask & (1 << side))) continue;
4239 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4240 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4241 R_Shadow_DrawEntityShadow(shadowentities[i]);
4244 if (numlightentities_noselfshadow)
4246 // render lighting using the depth texture as shadowmap
4247 // draw lighting in the unmasked areas
4248 R_Shadow_RenderMode_Lighting(false, false, true);
4249 for (i = 0;i < numlightentities_noselfshadow;i++)
4250 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4253 // render shadow casters into 6 sided depth texture
4254 if (numshadowentities_noselfshadow)
4256 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4258 R_Shadow_RenderMode_ShadowMap(side, false, size);
4259 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4260 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4264 // render lighting using the depth texture as shadowmap
4265 // draw lighting in the unmasked areas
4266 R_Shadow_RenderMode_Lighting(false, false, true);
4267 // draw lighting in the unmasked areas
4269 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4270 for (i = 0;i < numlightentities;i++)
4271 R_Shadow_DrawEntityLight(lightentities[i]);
4273 else if (castshadows && gl_stencil)
4275 // draw stencil shadow volumes to mask off pixels that are in shadow
4276 // so that they won't receive lighting
4277 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4278 R_Shadow_ClearStencil();
4280 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4281 for (i = 0;i < numshadowentities;i++)
4282 R_Shadow_DrawEntityShadow(shadowentities[i]);
4283 if (numlightentities_noselfshadow)
4285 // draw lighting in the unmasked areas
4286 R_Shadow_RenderMode_Lighting(true, false, false);
4287 for (i = 0;i < numlightentities_noselfshadow;i++)
4288 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4290 // optionally draw the illuminated areas
4291 // for performance analysis by level designers
4292 if (r_showlighting.integer && r_refdef.view.showdebug)
4294 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4295 for (i = 0;i < numlightentities_noselfshadow;i++)
4296 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4299 for (i = 0;i < numshadowentities_noselfshadow;i++)
4300 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4302 if (numsurfaces + numlightentities)
4304 // draw lighting in the unmasked areas
4305 R_Shadow_RenderMode_Lighting(true, false, false);
4307 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4308 for (i = 0;i < numlightentities;i++)
4309 R_Shadow_DrawEntityLight(lightentities[i]);
4314 if (numsurfaces + numlightentities)
4316 // draw lighting in the unmasked areas
4317 R_Shadow_RenderMode_Lighting(false, false, false);
4319 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4320 for (i = 0;i < numlightentities;i++)
4321 R_Shadow_DrawEntityLight(lightentities[i]);
4322 for (i = 0;i < numlightentities_noselfshadow;i++)
4323 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4328 void R_Shadow_DrawLightSprites(void);
4329 void R_ShadowVolumeLighting(qboolean visible)
4337 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4338 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) ||
4339 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4340 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4341 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4342 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4343 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4344 R_Shadow_FreeShadowMaps();
4346 if (r_editlights.integer)
4347 R_Shadow_DrawLightSprites();
4349 R_Shadow_RenderMode_Begin();
4351 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4352 if (r_shadow_debuglight.integer >= 0)
4354 lightindex = r_shadow_debuglight.integer;
4355 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4356 if (light && (light->flags & flag))
4357 R_DrawRTLight(&light->rtlight, visible);
4361 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4362 for (lightindex = 0;lightindex < range;lightindex++)
4364 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4365 if (light && (light->flags & flag))
4366 R_DrawRTLight(&light->rtlight, visible);
4369 if (r_refdef.scene.rtdlight)
4370 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4371 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4373 R_Shadow_RenderMode_End();
4376 extern const float r_screenvertex3f[12];
4377 extern void R_SetupView(qboolean allowwaterclippingplane);
4378 extern void R_ResetViewRendering3D(void);
4379 extern void R_ResetViewRendering2D(void);
4380 extern cvar_t r_shadows;
4381 extern cvar_t r_shadows_darken;
4382 extern cvar_t r_shadows_drawafterrtlighting;
4383 extern cvar_t r_shadows_castfrombmodels;
4384 extern cvar_t r_shadows_throwdistance;
4385 extern cvar_t r_shadows_throwdirection;
4386 void R_DrawModelShadows(void)
4389 float relativethrowdistance;
4390 entity_render_t *ent;
4391 vec3_t relativelightorigin;
4392 vec3_t relativelightdirection;
4393 vec3_t relativeshadowmins, relativeshadowmaxs;
4394 vec3_t tmp, shadowdir;
4396 if (!r_drawentities.integer || !gl_stencil)
4400 R_ResetViewRendering3D();
4401 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4402 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4403 R_Shadow_RenderMode_Begin();
4404 R_Shadow_RenderMode_ActiveLight(NULL);
4405 r_shadow_lightscissor[0] = r_refdef.view.x;
4406 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4407 r_shadow_lightscissor[2] = r_refdef.view.width;
4408 r_shadow_lightscissor[3] = r_refdef.view.height;
4409 R_Shadow_RenderMode_StencilShadowVolumes(false);
4412 if (r_shadows.integer == 2)
4414 Math_atov(r_shadows_throwdirection.string, shadowdir);
4415 VectorNormalize(shadowdir);
4418 R_Shadow_ClearStencil();
4420 for (i = 0;i < r_refdef.scene.numentities;i++)
4422 ent = r_refdef.scene.entities[i];
4424 // cast shadows from anything of the map (submodels are optional)
4425 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4427 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4428 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4429 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4430 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4431 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4434 if(ent->entitynumber != 0)
4436 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4437 int entnum, entnum2, recursion;
4438 entnum = entnum2 = ent->entitynumber;
4439 for(recursion = 32; recursion > 0; --recursion)
4441 entnum2 = cl.entities[entnum].state_current.tagentity;
4442 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4447 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4449 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4450 // transform into modelspace of OUR entity
4451 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4452 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4455 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4458 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4461 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4462 RSurf_ActiveModelEntity(ent, false, false);
4463 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4464 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4468 // not really the right mode, but this will disable any silly stencil features
4469 R_Shadow_RenderMode_End();
4471 // set up ortho view for rendering this pass
4472 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4473 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4474 //GL_ScissorTest(true);
4475 //R_Mesh_Matrix(&identitymatrix);
4476 //R_Mesh_ResetTextureState();
4477 R_ResetViewRendering2D();
4478 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4479 R_Mesh_ColorPointer(NULL, 0, 0);
4480 R_SetupGenericShader(false);
4482 // set up a darkening blend on shadowed areas
4483 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4484 //GL_DepthRange(0, 1);
4485 //GL_DepthTest(false);
4486 //GL_DepthMask(false);
4487 //GL_PolygonOffset(0, 0);CHECKGLERROR
4488 GL_Color(0, 0, 0, r_shadows_darken.value);
4489 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4490 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4491 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4492 qglStencilMask(~0);CHECKGLERROR
4493 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4494 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4496 // apply the blend to the shadowed areas
4497 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4499 // restore the viewport
4500 R_SetViewport(&r_refdef.view.viewport);
4502 // restore other state to normal
4503 //R_Shadow_RenderMode_End();
4506 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4509 vec3_t centerorigin;
4510 // if it's too close, skip it
4511 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4513 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4516 if (usequery && r_numqueries + 2 <= r_maxqueries)
4518 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4519 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4520 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4523 // 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
4524 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4525 qglDepthFunc(GL_ALWAYS);
4526 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);
4527 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4528 qglDepthFunc(GL_LEQUAL);
4529 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4530 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);
4531 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4534 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4537 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4540 GLint allpixels = 0, visiblepixels = 0;
4541 // now we have to check the query result
4542 if (rtlight->corona_queryindex_visiblepixels)
4545 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4546 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4548 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4549 if (visiblepixels < 1 || allpixels < 1)
4551 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4552 cscale *= rtlight->corona_visibility;
4556 // FIXME: these traces should scan all render entities instead of cl.world
4557 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4560 VectorScale(rtlight->color, cscale, color);
4561 if (VectorLength(color) > (1.0f / 256.0f))
4562 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);
4565 void R_DrawCoronas(void)
4573 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4575 if (r_waterstate.renderingscene)
4577 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4578 R_Mesh_Matrix(&identitymatrix);
4580 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4582 // check occlusion of coronas
4583 // use GL_ARB_occlusion_query if available
4584 // otherwise use raytraces
4586 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4589 GL_ColorMask(0,0,0,0);
4590 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4591 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4594 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4595 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4597 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4601 for (lightindex = 0;lightindex < range;lightindex++)
4603 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4606 rtlight = &light->rtlight;
4607 rtlight->corona_visibility = 0;
4608 rtlight->corona_queryindex_visiblepixels = 0;
4609 rtlight->corona_queryindex_allpixels = 0;
4610 if (!(rtlight->flags & flag))
4612 if (rtlight->corona <= 0)
4614 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4616 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4618 for (i = 0;i < r_refdef.scene.numlights;i++)
4620 rtlight = r_refdef.scene.lights[i];
4621 rtlight->corona_visibility = 0;
4622 rtlight->corona_queryindex_visiblepixels = 0;
4623 rtlight->corona_queryindex_allpixels = 0;
4624 if (!(rtlight->flags & flag))
4626 if (rtlight->corona <= 0)
4628 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4631 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4633 // now draw the coronas using the query data for intensity info
4634 for (lightindex = 0;lightindex < range;lightindex++)
4636 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4639 rtlight = &light->rtlight;
4640 if (rtlight->corona_visibility <= 0)
4642 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4644 for (i = 0;i < r_refdef.scene.numlights;i++)
4646 rtlight = r_refdef.scene.lights[i];
4647 if (rtlight->corona_visibility <= 0)
4649 if (gl_flashblend.integer)
4650 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4652 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4658 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4659 typedef struct suffixinfo_s
4662 qboolean flipx, flipy, flipdiagonal;
4665 static suffixinfo_t suffix[3][6] =
4668 {"px", false, false, false},
4669 {"nx", false, false, false},
4670 {"py", false, false, false},
4671 {"ny", false, false, false},
4672 {"pz", false, false, false},
4673 {"nz", false, false, false}
4676 {"posx", false, false, false},
4677 {"negx", false, false, false},
4678 {"posy", false, false, false},
4679 {"negy", false, false, false},
4680 {"posz", false, false, false},
4681 {"negz", false, false, false}
4684 {"rt", true, false, true},
4685 {"lf", false, true, true},
4686 {"ft", true, true, false},
4687 {"bk", false, false, false},
4688 {"up", true, false, true},
4689 {"dn", true, false, true}
4693 static int componentorder[4] = {0, 1, 2, 3};
4695 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4697 int i, j, cubemapsize;
4698 unsigned char *cubemappixels, *image_buffer;
4699 rtexture_t *cubemaptexture;
4701 // must start 0 so the first loadimagepixels has no requested width/height
4703 cubemappixels = NULL;
4704 cubemaptexture = NULL;
4705 // keep trying different suffix groups (posx, px, rt) until one loads
4706 for (j = 0;j < 3 && !cubemappixels;j++)
4708 // load the 6 images in the suffix group
4709 for (i = 0;i < 6;i++)
4711 // generate an image name based on the base and and suffix
4712 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4714 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4716 // an image loaded, make sure width and height are equal
4717 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4719 // if this is the first image to load successfully, allocate the cubemap memory
4720 if (!cubemappixels && image_width >= 1)
4722 cubemapsize = image_width;
4723 // note this clears to black, so unavailable sides are black
4724 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4726 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4728 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);
4731 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4733 Mem_Free(image_buffer);
4737 // if a cubemap loaded, upload it
4740 if (developer_loading.integer)
4741 Con_Printf("loading cubemap \"%s\"\n", basename);
4743 if (!r_shadow_filters_texturepool)
4744 r_shadow_filters_texturepool = R_AllocTexturePool();
4745 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4746 Mem_Free(cubemappixels);
4750 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4751 if (developer_loading.integer)
4753 Con_Printf("(tried tried images ");
4754 for (j = 0;j < 3;j++)
4755 for (i = 0;i < 6;i++)
4756 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4757 Con_Print(" and was unable to find any of them).\n");
4760 return cubemaptexture;
4763 rtexture_t *R_Shadow_Cubemap(const char *basename)
4766 for (i = 0;i < numcubemaps;i++)
4767 if (!strcasecmp(cubemaps[i].basename, basename))
4768 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4769 if (i >= MAX_CUBEMAPS)
4770 return r_texture_whitecube;
4772 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4773 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4774 return cubemaps[i].texture;
4777 void R_Shadow_FreeCubemaps(void)
4780 for (i = 0;i < numcubemaps;i++)
4782 if (developer_loading.integer)
4783 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4784 if (cubemaps[i].texture)
4785 R_FreeTexture(cubemaps[i].texture);
4789 R_FreeTexturePool(&r_shadow_filters_texturepool);
4792 dlight_t *R_Shadow_NewWorldLight(void)
4794 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4797 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)
4800 // validate parameters
4801 if (style < 0 || style >= MAX_LIGHTSTYLES)
4803 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4809 // copy to light properties
4810 VectorCopy(origin, light->origin);
4811 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4812 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4813 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4814 light->color[0] = max(color[0], 0);
4815 light->color[1] = max(color[1], 0);
4816 light->color[2] = max(color[2], 0);
4817 light->radius = max(radius, 0);
4818 light->style = style;
4819 light->shadow = shadowenable;
4820 light->corona = corona;
4821 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4822 light->coronasizescale = coronasizescale;
4823 light->ambientscale = ambientscale;
4824 light->diffusescale = diffusescale;
4825 light->specularscale = specularscale;
4826 light->flags = flags;
4828 // update renderable light data
4829 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4830 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);
4833 void R_Shadow_FreeWorldLight(dlight_t *light)
4835 if (r_shadow_selectedlight == light)
4836 r_shadow_selectedlight = NULL;
4837 R_RTLight_Uncompile(&light->rtlight);
4838 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4841 void R_Shadow_ClearWorldLights(void)
4845 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4846 for (lightindex = 0;lightindex < range;lightindex++)
4848 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4850 R_Shadow_FreeWorldLight(light);
4852 r_shadow_selectedlight = NULL;
4853 R_Shadow_FreeCubemaps();
4856 void R_Shadow_SelectLight(dlight_t *light)
4858 if (r_shadow_selectedlight)
4859 r_shadow_selectedlight->selected = false;
4860 r_shadow_selectedlight = light;
4861 if (r_shadow_selectedlight)
4862 r_shadow_selectedlight->selected = true;
4865 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4867 // this is never batched (there can be only one)
4868 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);
4871 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4878 // this is never batched (due to the ent parameter changing every time)
4879 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4880 const dlight_t *light = (dlight_t *)ent;
4883 VectorScale(light->color, intensity, spritecolor);
4884 if (VectorLength(spritecolor) < 0.1732f)
4885 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4886 if (VectorLength(spritecolor) > 1.0f)
4887 VectorNormalize(spritecolor);
4889 // draw light sprite
4890 if (light->cubemapname[0] && !light->shadow)
4891 pic = r_editlights_sprcubemapnoshadowlight;
4892 else if (light->cubemapname[0])
4893 pic = r_editlights_sprcubemaplight;
4894 else if (!light->shadow)
4895 pic = r_editlights_sprnoshadowlight;
4897 pic = r_editlights_sprlight;
4898 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);
4899 // draw selection sprite if light is selected
4900 if (light->selected)
4901 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);
4902 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4905 void R_Shadow_DrawLightSprites(void)
4909 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4910 for (lightindex = 0;lightindex < range;lightindex++)
4912 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4914 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4916 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4919 void R_Shadow_SelectLightInView(void)
4921 float bestrating, rating, temp[3];
4925 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4928 for (lightindex = 0;lightindex < range;lightindex++)
4930 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4933 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4934 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4937 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4938 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4940 bestrating = rating;
4945 R_Shadow_SelectLight(best);
4948 void R_Shadow_LoadWorldLights(void)
4950 int n, a, style, shadow, flags;
4951 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4952 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4953 if (cl.worldmodel == NULL)
4955 Con_Print("No map loaded.\n");
4958 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4959 strlcat (name, ".rtlights", sizeof (name));
4960 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4970 for (;COM_Parse(t, true) && strcmp(
4971 if (COM_Parse(t, true))
4973 if (com_token[0] == '!')
4976 origin[0] = atof(com_token+1);
4979 origin[0] = atof(com_token);
4984 while (*s && *s != '\n' && *s != '\r')
4990 // check for modifier flags
4997 #if _MSC_VER >= 1400
4998 #define sscanf sscanf_s
5000 cubemapname[sizeof(cubemapname)-1] = 0;
5001 #if MAX_QPATH != 128
5002 #error update this code if MAX_QPATH changes
5004 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
5005 #if _MSC_VER >= 1400
5006 , sizeof(cubemapname)
5008 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5011 flags = LIGHTFLAG_REALTIMEMODE;
5019 coronasizescale = 0.25f;
5021 VectorClear(angles);
5024 if (a < 9 || !strcmp(cubemapname, "\"\""))
5026 // remove quotes on cubemapname
5027 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5030 namelen = strlen(cubemapname) - 2;
5031 memmove(cubemapname, cubemapname + 1, namelen);
5032 cubemapname[namelen] = '\0';
5036 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);
5039 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5047 Con_Printf("invalid rtlights file \"%s\"\n", name);
5048 Mem_Free(lightsstring);
5052 void R_Shadow_SaveWorldLights(void)
5056 size_t bufchars, bufmaxchars;
5058 char name[MAX_QPATH];
5059 char line[MAX_INPUTLINE];
5060 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5061 // I hate lines which are 3 times my screen size :( --blub
5064 if (cl.worldmodel == NULL)
5066 Con_Print("No map loaded.\n");
5069 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5070 strlcat (name, ".rtlights", sizeof (name));
5071 bufchars = bufmaxchars = 0;
5073 for (lightindex = 0;lightindex < range;lightindex++)
5075 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5078 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5079 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);
5080 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5081 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]);
5083 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);
5084 if (bufchars + strlen(line) > bufmaxchars)
5086 bufmaxchars = bufchars + strlen(line) + 2048;
5088 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5092 memcpy(buf, oldbuf, bufchars);
5098 memcpy(buf + bufchars, line, strlen(line));
5099 bufchars += strlen(line);
5103 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5108 void R_Shadow_LoadLightsFile(void)
5111 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5112 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5113 if (cl.worldmodel == NULL)
5115 Con_Print("No map loaded.\n");
5118 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5119 strlcat (name, ".lights", sizeof (name));
5120 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5128 while (*s && *s != '\n' && *s != '\r')
5134 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);
5138 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);
5141 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5142 radius = bound(15, radius, 4096);
5143 VectorScale(color, (2.0f / (8388608.0f)), color);
5144 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5152 Con_Printf("invalid lights file \"%s\"\n", name);
5153 Mem_Free(lightsstring);
5157 // tyrlite/hmap2 light types in the delay field
5158 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5160 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5162 int entnum, style, islight, skin, pflags, effects, type, n;
5165 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5166 char key[256], value[MAX_INPUTLINE];
5168 if (cl.worldmodel == NULL)
5170 Con_Print("No map loaded.\n");
5173 // try to load a .ent file first
5174 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5175 strlcat (key, ".ent", sizeof (key));
5176 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5177 // and if that is not found, fall back to the bsp file entity string
5179 data = cl.worldmodel->brush.entities;
5182 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5184 type = LIGHTTYPE_MINUSX;
5185 origin[0] = origin[1] = origin[2] = 0;
5186 originhack[0] = originhack[1] = originhack[2] = 0;
5187 angles[0] = angles[1] = angles[2] = 0;
5188 color[0] = color[1] = color[2] = 1;
5189 light[0] = light[1] = light[2] = 1;light[3] = 300;
5190 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5200 if (!COM_ParseToken_Simple(&data, false, false))
5202 if (com_token[0] == '}')
5203 break; // end of entity
5204 if (com_token[0] == '_')
5205 strlcpy(key, com_token + 1, sizeof(key));
5207 strlcpy(key, com_token, sizeof(key));
5208 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5209 key[strlen(key)-1] = 0;
5210 if (!COM_ParseToken_Simple(&data, false, false))
5212 strlcpy(value, com_token, sizeof(value));
5214 // now that we have the key pair worked out...
5215 if (!strcmp("light", key))
5217 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5221 light[0] = vec[0] * (1.0f / 256.0f);
5222 light[1] = vec[0] * (1.0f / 256.0f);
5223 light[2] = vec[0] * (1.0f / 256.0f);
5229 light[0] = vec[0] * (1.0f / 255.0f);
5230 light[1] = vec[1] * (1.0f / 255.0f);
5231 light[2] = vec[2] * (1.0f / 255.0f);
5235 else if (!strcmp("delay", key))
5237 else if (!strcmp("origin", key))
5238 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5239 else if (!strcmp("angle", key))
5240 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5241 else if (!strcmp("angles", key))
5242 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5243 else if (!strcmp("color", key))
5244 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5245 else if (!strcmp("wait", key))
5246 fadescale = atof(value);
5247 else if (!strcmp("classname", key))
5249 if (!strncmp(value, "light", 5))
5252 if (!strcmp(value, "light_fluoro"))
5257 overridecolor[0] = 1;
5258 overridecolor[1] = 1;
5259 overridecolor[2] = 1;
5261 if (!strcmp(value, "light_fluorospark"))
5266 overridecolor[0] = 1;
5267 overridecolor[1] = 1;
5268 overridecolor[2] = 1;
5270 if (!strcmp(value, "light_globe"))
5275 overridecolor[0] = 1;
5276 overridecolor[1] = 0.8;
5277 overridecolor[2] = 0.4;
5279 if (!strcmp(value, "light_flame_large_yellow"))
5284 overridecolor[0] = 1;
5285 overridecolor[1] = 0.5;
5286 overridecolor[2] = 0.1;
5288 if (!strcmp(value, "light_flame_small_yellow"))
5293 overridecolor[0] = 1;
5294 overridecolor[1] = 0.5;
5295 overridecolor[2] = 0.1;
5297 if (!strcmp(value, "light_torch_small_white"))
5302 overridecolor[0] = 1;
5303 overridecolor[1] = 0.5;
5304 overridecolor[2] = 0.1;
5306 if (!strcmp(value, "light_torch_small_walltorch"))
5311 overridecolor[0] = 1;
5312 overridecolor[1] = 0.5;
5313 overridecolor[2] = 0.1;
5317 else if (!strcmp("style", key))
5318 style = atoi(value);
5319 else if (!strcmp("skin", key))
5320 skin = (int)atof(value);
5321 else if (!strcmp("pflags", key))
5322 pflags = (int)atof(value);
5323 else if (!strcmp("effects", key))
5324 effects = (int)atof(value);
5325 else if (cl.worldmodel->type == mod_brushq3)
5327 if (!strcmp("scale", key))
5328 lightscale = atof(value);
5329 if (!strcmp("fade", key))
5330 fadescale = atof(value);
5335 if (lightscale <= 0)
5339 if (color[0] == color[1] && color[0] == color[2])
5341 color[0] *= overridecolor[0];
5342 color[1] *= overridecolor[1];
5343 color[2] *= overridecolor[2];
5345 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5346 color[0] = color[0] * light[0];
5347 color[1] = color[1] * light[1];
5348 color[2] = color[2] * light[2];
5351 case LIGHTTYPE_MINUSX:
5353 case LIGHTTYPE_RECIPX:
5355 VectorScale(color, (1.0f / 16.0f), color);
5357 case LIGHTTYPE_RECIPXX:
5359 VectorScale(color, (1.0f / 16.0f), color);
5362 case LIGHTTYPE_NONE:
5366 case LIGHTTYPE_MINUSXX:
5369 VectorAdd(origin, originhack, origin);
5371 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);
5374 Mem_Free(entfiledata);
5378 void R_Shadow_SetCursorLocationForView(void)
5381 vec3_t dest, endpos;
5383 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5384 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5385 if (trace.fraction < 1)
5387 dist = trace.fraction * r_editlights_cursordistance.value;
5388 push = r_editlights_cursorpushback.value;
5392 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5393 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5397 VectorClear( endpos );
5399 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5400 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5401 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5404 void R_Shadow_UpdateWorldLightSelection(void)
5406 if (r_editlights.integer)
5408 R_Shadow_SetCursorLocationForView();
5409 R_Shadow_SelectLightInView();
5412 R_Shadow_SelectLight(NULL);
5415 void R_Shadow_EditLights_Clear_f(void)
5417 R_Shadow_ClearWorldLights();
5420 void R_Shadow_EditLights_Reload_f(void)
5424 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5425 R_Shadow_ClearWorldLights();
5426 R_Shadow_LoadWorldLights();
5427 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5429 R_Shadow_LoadLightsFile();
5430 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5431 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5435 void R_Shadow_EditLights_Save_f(void)
5439 R_Shadow_SaveWorldLights();
5442 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5444 R_Shadow_ClearWorldLights();
5445 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5448 void R_Shadow_EditLights_ImportLightsFile_f(void)
5450 R_Shadow_ClearWorldLights();
5451 R_Shadow_LoadLightsFile();
5454 void R_Shadow_EditLights_Spawn_f(void)
5457 if (!r_editlights.integer)
5459 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5462 if (Cmd_Argc() != 1)
5464 Con_Print("r_editlights_spawn does not take parameters\n");
5467 color[0] = color[1] = color[2] = 1;
5468 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5471 void R_Shadow_EditLights_Edit_f(void)
5473 vec3_t origin, angles, color;
5474 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5475 int style, shadows, flags, normalmode, realtimemode;
5476 char cubemapname[MAX_INPUTLINE];
5477 if (!r_editlights.integer)
5479 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5482 if (!r_shadow_selectedlight)
5484 Con_Print("No selected light.\n");
5487 VectorCopy(r_shadow_selectedlight->origin, origin);
5488 VectorCopy(r_shadow_selectedlight->angles, angles);
5489 VectorCopy(r_shadow_selectedlight->color, color);
5490 radius = r_shadow_selectedlight->radius;
5491 style = r_shadow_selectedlight->style;
5492 if (r_shadow_selectedlight->cubemapname)
5493 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5496 shadows = r_shadow_selectedlight->shadow;
5497 corona = r_shadow_selectedlight->corona;
5498 coronasizescale = r_shadow_selectedlight->coronasizescale;
5499 ambientscale = r_shadow_selectedlight->ambientscale;
5500 diffusescale = r_shadow_selectedlight->diffusescale;
5501 specularscale = r_shadow_selectedlight->specularscale;
5502 flags = r_shadow_selectedlight->flags;
5503 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5504 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5505 if (!strcmp(Cmd_Argv(1), "origin"))
5507 if (Cmd_Argc() != 5)
5509 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5512 origin[0] = atof(Cmd_Argv(2));
5513 origin[1] = atof(Cmd_Argv(3));
5514 origin[2] = atof(Cmd_Argv(4));
5516 else if (!strcmp(Cmd_Argv(1), "originx"))
5518 if (Cmd_Argc() != 3)
5520 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5523 origin[0] = atof(Cmd_Argv(2));
5525 else if (!strcmp(Cmd_Argv(1), "originy"))
5527 if (Cmd_Argc() != 3)
5529 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5532 origin[1] = atof(Cmd_Argv(2));
5534 else if (!strcmp(Cmd_Argv(1), "originz"))
5536 if (Cmd_Argc() != 3)
5538 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5541 origin[2] = atof(Cmd_Argv(2));
5543 else if (!strcmp(Cmd_Argv(1), "move"))
5545 if (Cmd_Argc() != 5)
5547 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5550 origin[0] += atof(Cmd_Argv(2));
5551 origin[1] += atof(Cmd_Argv(3));
5552 origin[2] += atof(Cmd_Argv(4));
5554 else if (!strcmp(Cmd_Argv(1), "movex"))
5556 if (Cmd_Argc() != 3)
5558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5561 origin[0] += atof(Cmd_Argv(2));
5563 else if (!strcmp(Cmd_Argv(1), "movey"))
5565 if (Cmd_Argc() != 3)
5567 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5570 origin[1] += atof(Cmd_Argv(2));
5572 else if (!strcmp(Cmd_Argv(1), "movez"))
5574 if (Cmd_Argc() != 3)
5576 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5579 origin[2] += atof(Cmd_Argv(2));
5581 else if (!strcmp(Cmd_Argv(1), "angles"))
5583 if (Cmd_Argc() != 5)
5585 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5588 angles[0] = atof(Cmd_Argv(2));
5589 angles[1] = atof(Cmd_Argv(3));
5590 angles[2] = atof(Cmd_Argv(4));
5592 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5594 if (Cmd_Argc() != 3)
5596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599 angles[0] = atof(Cmd_Argv(2));
5601 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5603 if (Cmd_Argc() != 3)
5605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5608 angles[1] = atof(Cmd_Argv(2));
5610 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5612 if (Cmd_Argc() != 3)
5614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5617 angles[2] = atof(Cmd_Argv(2));
5619 else if (!strcmp(Cmd_Argv(1), "color"))
5621 if (Cmd_Argc() != 5)
5623 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5626 color[0] = atof(Cmd_Argv(2));
5627 color[1] = atof(Cmd_Argv(3));
5628 color[2] = atof(Cmd_Argv(4));
5630 else if (!strcmp(Cmd_Argv(1), "radius"))
5632 if (Cmd_Argc() != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5637 radius = atof(Cmd_Argv(2));
5639 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5641 if (Cmd_Argc() == 3)
5643 double scale = atof(Cmd_Argv(2));
5650 if (Cmd_Argc() != 5)
5652 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5655 color[0] *= atof(Cmd_Argv(2));
5656 color[1] *= atof(Cmd_Argv(3));
5657 color[2] *= atof(Cmd_Argv(4));
5660 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5662 if (Cmd_Argc() != 3)
5664 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5667 radius *= atof(Cmd_Argv(2));
5669 else if (!strcmp(Cmd_Argv(1), "style"))
5671 if (Cmd_Argc() != 3)
5673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5676 style = atoi(Cmd_Argv(2));
5678 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 if (Cmd_Argc() == 3)
5686 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5690 else if (!strcmp(Cmd_Argv(1), "shadows"))
5692 if (Cmd_Argc() != 3)
5694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5697 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5699 else if (!strcmp(Cmd_Argv(1), "corona"))
5701 if (Cmd_Argc() != 3)
5703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5706 corona = atof(Cmd_Argv(2));
5708 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 coronasizescale = atof(Cmd_Argv(2));
5717 else if (!strcmp(Cmd_Argv(1), "ambient"))
5719 if (Cmd_Argc() != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5724 ambientscale = atof(Cmd_Argv(2));
5726 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5728 if (Cmd_Argc() != 3)
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 diffusescale = atof(Cmd_Argv(2));
5735 else if (!strcmp(Cmd_Argv(1), "specular"))
5737 if (Cmd_Argc() != 3)
5739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5742 specularscale = atof(Cmd_Argv(2));
5744 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5746 if (Cmd_Argc() != 3)
5748 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5751 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5753 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5755 if (Cmd_Argc() != 3)
5757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5760 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5764 Con_Print("usage: r_editlights_edit [property] [value]\n");
5765 Con_Print("Selected light's properties:\n");
5766 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5767 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5768 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5769 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5770 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5771 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5772 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5773 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5774 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5775 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5776 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5777 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5778 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5779 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5782 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5783 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5786 void R_Shadow_EditLights_EditAll_f(void)
5792 if (!r_editlights.integer)
5794 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5798 // EditLights doesn't seem to have a "remove" command or something so:
5799 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5800 for (lightindex = 0;lightindex < range;lightindex++)
5802 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5805 R_Shadow_SelectLight(light);
5806 R_Shadow_EditLights_Edit_f();
5810 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5812 int lightnumber, lightcount;
5813 size_t lightindex, range;
5817 if (!r_editlights.integer)
5819 x = vid_conwidth.value - 240;
5821 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5824 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5825 for (lightindex = 0;lightindex < range;lightindex++)
5827 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5830 if (light == r_shadow_selectedlight)
5831 lightnumber = lightindex;
5834 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;
5835 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;
5837 if (r_shadow_selectedlight == NULL)
5839 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;
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5845 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;
5846 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;
5847 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;
5848 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;
5849 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;
5850 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;
5851 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;
5852 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;
5853 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;
5856 void R_Shadow_EditLights_ToggleShadow_f(void)
5858 if (!r_editlights.integer)
5860 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5863 if (!r_shadow_selectedlight)
5865 Con_Print("No selected light.\n");
5868 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);
5871 void R_Shadow_EditLights_ToggleCorona_f(void)
5873 if (!r_editlights.integer)
5875 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5878 if (!r_shadow_selectedlight)
5880 Con_Print("No selected light.\n");
5883 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);
5886 void R_Shadow_EditLights_Remove_f(void)
5888 if (!r_editlights.integer)
5890 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5893 if (!r_shadow_selectedlight)
5895 Con_Print("No selected light.\n");
5898 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5899 r_shadow_selectedlight = NULL;
5902 void R_Shadow_EditLights_Help_f(void)
5905 "Documentation on r_editlights system:\n"
5907 "r_editlights : enable/disable editing mode\n"
5908 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5909 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5910 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5911 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5912 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5914 "r_editlights_help : this help\n"
5915 "r_editlights_clear : remove all lights\n"
5916 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5917 "r_editlights_save : save to .rtlights file\n"
5918 "r_editlights_spawn : create a light with default settings\n"
5919 "r_editlights_edit command : edit selected light - more documentation below\n"
5920 "r_editlights_remove : remove selected light\n"
5921 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5922 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5923 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5925 "origin x y z : set light location\n"
5926 "originx x: set x component of light location\n"
5927 "originy y: set y component of light location\n"
5928 "originz z: set z component of light location\n"
5929 "move x y z : adjust light location\n"
5930 "movex x: adjust x component of light location\n"
5931 "movey y: adjust y component of light location\n"
5932 "movez z: adjust z component of light location\n"
5933 "angles x y z : set light angles\n"
5934 "anglesx x: set x component of light angles\n"
5935 "anglesy y: set y component of light angles\n"
5936 "anglesz z: set z component of light angles\n"
5937 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5938 "radius radius : set radius (size) of light\n"
5939 "colorscale grey : multiply color of light (1 does nothing)\n"
5940 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5941 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5942 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5943 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5944 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5945 "shadows 1/0 : turn on/off shadows\n"
5946 "corona n : set corona intensity\n"
5947 "coronasize n : set corona size (0-1)\n"
5948 "ambient n : set ambient intensity (0-1)\n"
5949 "diffuse n : set diffuse intensity (0-1)\n"
5950 "specular n : set specular intensity (0-1)\n"
5951 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5952 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5953 "<nothing> : print light properties to console\n"
5957 void R_Shadow_EditLights_CopyInfo_f(void)
5959 if (!r_editlights.integer)
5961 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5964 if (!r_shadow_selectedlight)
5966 Con_Print("No selected light.\n");
5969 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5970 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5971 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5972 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5973 if (r_shadow_selectedlight->cubemapname)
5974 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5976 r_shadow_bufferlight.cubemapname[0] = 0;
5977 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5978 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5979 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5980 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5981 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5982 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5983 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5986 void R_Shadow_EditLights_PasteInfo_f(void)
5988 if (!r_editlights.integer)
5990 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5993 if (!r_shadow_selectedlight)
5995 Con_Print("No selected light.\n");
5998 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);
6001 void R_Shadow_EditLights_Init(void)
6003 Cvar_RegisterVariable(&r_editlights);
6004 Cvar_RegisterVariable(&r_editlights_cursordistance);
6005 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6006 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6007 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6008 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6009 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6010 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6011 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)");
6012 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6013 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6014 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6015 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)");
6016 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6017 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6018 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6019 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6020 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6021 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6022 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)");
6028 =============================================================================
6032 =============================================================================
6035 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6037 VectorClear(diffusecolor);
6038 VectorClear(diffusenormal);
6040 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6042 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6043 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6046 VectorSet(ambientcolor, 1, 1, 1);
6053 for (i = 0;i < r_refdef.scene.numlights;i++)
6055 light = r_refdef.scene.lights[i];
6056 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6057 f = 1 - VectorLength2(v);
6058 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6059 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);