3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapprecision;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 rtexture_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmaprectangletexture;
248 rtexture_t *r_shadow_shadowmap2dtexture;
249 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 // lights are reloaded when this changes
255 char r_shadow_mapname[MAX_QPATH];
257 // used only for light filters (cubemaps)
258 rtexturepool_t *r_shadow_filters_texturepool;
260 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
261 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
262 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
263 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
264 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
265 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
266 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
267 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
268 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
269 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
270 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
271 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
273 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
274 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
275 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
276 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
277 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
278 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
279 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
280 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
281 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
282 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
283 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
284 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
285 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
286 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
287 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
288 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
289 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
290 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
291 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
292 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
293 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
294 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
295 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_quality = {CVAR_SAVE, "r_shadow_shadowmapping_quality", "0", "Makes shadowmaps to have initial resolution of this number of pixels per light source radius unit. Like, light with radius 200 will have initial shadowmaps with resolution 200. This overrides default LOD-based shadowmaps resolution formula. Might be good in some situations but futher testing is required."};
297 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
298 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
299 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
300 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
301 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
302 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
303 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
304 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
305 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
306 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)"};
307 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)"};
308 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
309 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"};
310 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
311 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
312 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
313 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
314 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
315 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
316 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
317 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
318 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
319 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
321 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
322 #define ATTENTABLESIZE 256
323 // 1D gradient, 2D circle and 3D sphere attenuation textures
324 #define ATTEN1DSIZE 32
325 #define ATTEN2DSIZE 64
326 #define ATTEN3DSIZE 32
328 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
329 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
330 static float r_shadow_attentable[ATTENTABLESIZE+1];
332 rtlight_t *r_shadow_compilingrtlight;
333 static memexpandablearray_t r_shadow_worldlightsarray;
334 dlight_t *r_shadow_selectedlight;
335 dlight_t r_shadow_bufferlight;
336 vec3_t r_editlights_cursorlocation;
338 extern int con_vislines;
340 typedef struct cubemapinfo_s
347 #define MAX_CUBEMAPS 256
348 static int numcubemaps;
349 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 // VorteX: custom editor light sprites
362 #define EDLIGHTSPRSIZE 8
363 cachepic_t *r_editlights_sprcursor;
364 cachepic_t *r_editlights_sprlight;
365 cachepic_t *r_editlights_sprnoshadowlight;
366 cachepic_t *r_editlights_sprcubemaplight;
367 cachepic_t *r_editlights_sprcubemapnoshadowlight;
368 cachepic_t *r_editlights_sprselection;
370 void R_Shadow_SetShadowMode(void)
372 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
373 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
374 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
375 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
376 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
385 if(r_shadow_shadowmapfilterquality < 0)
387 if(strstr(gl_vendor, "NVIDIA"))
389 r_shadow_shadowmapsampler = gl_support_arb_shadow;
390 r_shadow_shadowmappcf = 1;
392 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
393 r_shadow_shadowmappcf = 1;
394 else if(strstr(gl_vendor, "ATI"))
395 r_shadow_shadowmappcf = 1;
397 r_shadow_shadowmapsampler = gl_support_arb_shadow;
401 switch (r_shadow_shadowmapfilterquality)
404 r_shadow_shadowmapsampler = gl_support_arb_shadow;
407 r_shadow_shadowmapsampler = gl_support_arb_shadow;
408 r_shadow_shadowmappcf = 1;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 2;
418 switch (r_shadow_shadowmaptexturetype)
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
424 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
427 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
430 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
432 else if(gl_texturerectangle)
433 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
435 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
441 void R_Shadow_FreeShadowMaps(void)
445 R_Shadow_SetShadowMode();
447 if (r_shadow_fborectangle)
448 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
449 r_shadow_fborectangle = 0;
453 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
456 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
457 if (r_shadow_fbocubeside[i])
458 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
459 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
462 if (r_shadow_shadowmaprectangletexture)
463 R_FreeTexture(r_shadow_shadowmaprectangletexture);
464 r_shadow_shadowmaprectangletexture = NULL;
466 if (r_shadow_shadowmap2dtexture)
467 R_FreeTexture(r_shadow_shadowmap2dtexture);
468 r_shadow_shadowmap2dtexture = NULL;
470 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
471 if (r_shadow_shadowmapcubetexture[i])
472 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
473 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
475 if (r_shadow_shadowmapvsdcttexture)
476 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
477 r_shadow_shadowmapvsdcttexture = NULL;
482 void r_shadow_start(void)
484 // allocate vertex processing arrays
486 r_shadow_attenuationgradienttexture = NULL;
487 r_shadow_attenuation2dtexture = NULL;
488 r_shadow_attenuation3dtexture = NULL;
489 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
490 r_shadow_shadowmaprectangletexture = NULL;
491 r_shadow_shadowmap2dtexture = NULL;
492 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
493 r_shadow_shadowmapvsdcttexture = NULL;
494 r_shadow_shadowmapmaxsize = 0;
495 r_shadow_shadowmapsize = 0;
496 r_shadow_shadowmaplod = 0;
497 r_shadow_shadowmapfilterquality = -1;
498 r_shadow_shadowmaptexturetype = -1;
499 r_shadow_shadowmapprecision = 0;
500 r_shadow_shadowmapvsdct = false;
501 r_shadow_shadowmapsampler = false;
502 r_shadow_shadowmappcf = 0;
503 r_shadow_fborectangle = 0;
505 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
507 R_Shadow_FreeShadowMaps();
509 r_shadow_texturepool = NULL;
510 r_shadow_filters_texturepool = NULL;
511 R_Shadow_ValidateCvars();
512 R_Shadow_MakeTextures();
513 maxshadowtriangles = 0;
514 shadowelements = NULL;
515 maxshadowvertices = 0;
516 shadowvertex3f = NULL;
524 shadowmarklist = NULL;
529 shadowsideslist = NULL;
530 r_shadow_buffer_numleafpvsbytes = 0;
531 r_shadow_buffer_visitingleafpvs = NULL;
532 r_shadow_buffer_leafpvs = NULL;
533 r_shadow_buffer_leaflist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 r_shadow_buffer_surfacepvs = NULL;
536 r_shadow_buffer_surfacelist = NULL;
537 r_shadow_buffer_surfacesides = NULL;
538 r_shadow_buffer_numshadowtrispvsbytes = 0;
539 r_shadow_buffer_shadowtrispvs = NULL;
540 r_shadow_buffer_numlighttrispvsbytes = 0;
541 r_shadow_buffer_lighttrispvs = NULL;
544 void r_shadow_shutdown(void)
547 R_Shadow_UncompileWorldLights();
549 R_Shadow_FreeShadowMaps();
553 r_shadow_attenuationgradienttexture = NULL;
554 r_shadow_attenuation2dtexture = NULL;
555 r_shadow_attenuation3dtexture = NULL;
556 R_FreeTexturePool(&r_shadow_texturepool);
557 R_FreeTexturePool(&r_shadow_filters_texturepool);
558 maxshadowtriangles = 0;
560 Mem_Free(shadowelements);
561 shadowelements = NULL;
563 Mem_Free(shadowvertex3f);
564 shadowvertex3f = NULL;
567 Mem_Free(vertexupdate);
570 Mem_Free(vertexremap);
576 Mem_Free(shadowmark);
579 Mem_Free(shadowmarklist);
580 shadowmarklist = NULL;
585 Mem_Free(shadowsides);
588 Mem_Free(shadowsideslist);
589 shadowsideslist = NULL;
590 r_shadow_buffer_numleafpvsbytes = 0;
591 if (r_shadow_buffer_visitingleafpvs)
592 Mem_Free(r_shadow_buffer_visitingleafpvs);
593 r_shadow_buffer_visitingleafpvs = NULL;
594 if (r_shadow_buffer_leafpvs)
595 Mem_Free(r_shadow_buffer_leafpvs);
596 r_shadow_buffer_leafpvs = NULL;
597 if (r_shadow_buffer_leaflist)
598 Mem_Free(r_shadow_buffer_leaflist);
599 r_shadow_buffer_leaflist = NULL;
600 r_shadow_buffer_numsurfacepvsbytes = 0;
601 if (r_shadow_buffer_surfacepvs)
602 Mem_Free(r_shadow_buffer_surfacepvs);
603 r_shadow_buffer_surfacepvs = NULL;
604 if (r_shadow_buffer_surfacelist)
605 Mem_Free(r_shadow_buffer_surfacelist);
606 r_shadow_buffer_surfacelist = NULL;
607 if (r_shadow_buffer_surfacesides)
608 Mem_Free(r_shadow_buffer_surfacesides);
609 r_shadow_buffer_surfacesides = NULL;
610 r_shadow_buffer_numshadowtrispvsbytes = 0;
611 if (r_shadow_buffer_shadowtrispvs)
612 Mem_Free(r_shadow_buffer_shadowtrispvs);
613 r_shadow_buffer_numlighttrispvsbytes = 0;
614 if (r_shadow_buffer_lighttrispvs)
615 Mem_Free(r_shadow_buffer_lighttrispvs);
618 void r_shadow_newmap(void)
620 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
621 R_Shadow_EditLights_Reload_f();
624 void R_Shadow_Help_f(void)
627 "Documentation on r_shadow system:\n"
629 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
630 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
631 "r_shadow_debuglight : render only this light number (-1 = all)\n"
632 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
633 "r_shadow_gloss2intensity : brightness of forced gloss\n"
634 "r_shadow_glossintensity : brightness of textured gloss\n"
635 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
636 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
637 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
638 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
639 "r_shadow_portallight : use portal visibility for static light precomputation\n"
640 "r_shadow_projectdistance : shadow volume projection distance\n"
641 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
642 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
643 "r_shadow_realtime_world : use high quality world lighting mode\n"
644 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
645 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
646 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
647 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
648 "r_shadow_scissor : use scissor optimization\n"
649 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
650 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
651 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
652 "r_showlighting : useful for performance testing; bright = slow!\n"
653 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
655 "r_shadow_help : this help\n"
659 void R_Shadow_Init(void)
661 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
662 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
663 Cvar_RegisterVariable(&r_shadow_usenormalmap);
664 Cvar_RegisterVariable(&r_shadow_debuglight);
665 Cvar_RegisterVariable(&r_shadow_gloss);
666 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
667 Cvar_RegisterVariable(&r_shadow_glossintensity);
668 Cvar_RegisterVariable(&r_shadow_glossexponent);
669 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
670 Cvar_RegisterVariable(&r_shadow_glossexact);
671 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
672 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
673 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
674 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
675 Cvar_RegisterVariable(&r_shadow_portallight);
676 Cvar_RegisterVariable(&r_shadow_projectdistance);
677 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
678 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
679 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
680 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
681 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
682 Cvar_RegisterVariable(&r_shadow_realtime_world);
683 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
684 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
685 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
686 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
687 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
688 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
689 Cvar_RegisterVariable(&r_shadow_scissor);
690 Cvar_RegisterVariable(&r_shadow_shadowmapping);
691 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
692 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
693 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
694 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
695 Cvar_RegisterVariable(&r_shadow_shadowmapping_quality);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
705 Cvar_RegisterVariable(&r_shadow_culltriangles);
706 Cvar_RegisterVariable(&r_shadow_polygonfactor);
707 Cvar_RegisterVariable(&r_shadow_polygonoffset);
708 Cvar_RegisterVariable(&r_shadow_texture3d);
709 Cvar_RegisterVariable(&r_coronas);
710 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
711 Cvar_RegisterVariable(&r_coronas_occlusionquery);
712 Cvar_RegisterVariable(&gl_flashblend);
713 Cvar_RegisterVariable(&gl_ext_separatestencil);
714 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
715 if (gamemode == GAME_TENEBRAE)
717 Cvar_SetValue("r_shadow_gloss", 2);
718 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
720 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
721 R_Shadow_EditLights_Init();
722 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
723 maxshadowtriangles = 0;
724 shadowelements = NULL;
725 maxshadowvertices = 0;
726 shadowvertex3f = NULL;
734 shadowmarklist = NULL;
739 shadowsideslist = NULL;
740 r_shadow_buffer_numleafpvsbytes = 0;
741 r_shadow_buffer_visitingleafpvs = NULL;
742 r_shadow_buffer_leafpvs = NULL;
743 r_shadow_buffer_leaflist = NULL;
744 r_shadow_buffer_numsurfacepvsbytes = 0;
745 r_shadow_buffer_surfacepvs = NULL;
746 r_shadow_buffer_surfacelist = NULL;
747 r_shadow_buffer_surfacesides = NULL;
748 r_shadow_buffer_shadowtrispvs = NULL;
749 r_shadow_buffer_lighttrispvs = NULL;
750 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
753 matrix4x4_t matrix_attenuationxyz =
756 {0.5, 0.0, 0.0, 0.5},
757 {0.0, 0.5, 0.0, 0.5},
758 {0.0, 0.0, 0.5, 0.5},
763 matrix4x4_t matrix_attenuationz =
766 {0.0, 0.0, 0.5, 0.5},
767 {0.0, 0.0, 0.0, 0.5},
768 {0.0, 0.0, 0.0, 0.5},
773 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
775 numvertices = ((numvertices + 255) & ~255) * vertscale;
776 numtriangles = ((numtriangles + 255) & ~255) * triscale;
777 // make sure shadowelements is big enough for this volume
778 if (maxshadowtriangles < numtriangles)
780 maxshadowtriangles = numtriangles;
782 Mem_Free(shadowelements);
783 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
785 // make sure shadowvertex3f is big enough for this volume
786 if (maxshadowvertices < numvertices)
788 maxshadowvertices = numvertices;
790 Mem_Free(shadowvertex3f);
791 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
795 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
797 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
798 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
799 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
800 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
801 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
803 if (r_shadow_buffer_visitingleafpvs)
804 Mem_Free(r_shadow_buffer_visitingleafpvs);
805 if (r_shadow_buffer_leafpvs)
806 Mem_Free(r_shadow_buffer_leafpvs);
807 if (r_shadow_buffer_leaflist)
808 Mem_Free(r_shadow_buffer_leaflist);
809 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
810 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
811 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
812 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
814 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
816 if (r_shadow_buffer_surfacepvs)
817 Mem_Free(r_shadow_buffer_surfacepvs);
818 if (r_shadow_buffer_surfacelist)
819 Mem_Free(r_shadow_buffer_surfacelist);
820 if (r_shadow_buffer_surfacesides)
821 Mem_Free(r_shadow_buffer_surfacesides);
822 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
823 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
824 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
825 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
827 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
829 if (r_shadow_buffer_shadowtrispvs)
830 Mem_Free(r_shadow_buffer_shadowtrispvs);
831 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
832 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
834 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
836 if (r_shadow_buffer_lighttrispvs)
837 Mem_Free(r_shadow_buffer_lighttrispvs);
838 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
839 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
843 void R_Shadow_PrepareShadowMark(int numtris)
845 // make sure shadowmark is big enough for this volume
846 if (maxshadowmark < numtris)
848 maxshadowmark = numtris;
850 Mem_Free(shadowmark);
852 Mem_Free(shadowmarklist);
853 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
854 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
858 // if shadowmarkcount wrapped we clear the array and adjust accordingly
859 if (shadowmarkcount == 0)
862 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
867 void R_Shadow_PrepareShadowSides(int numtris)
869 if (maxshadowsides < numtris)
871 maxshadowsides = numtris;
873 Mem_Free(shadowsides);
875 Mem_Free(shadowsideslist);
876 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
877 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
882 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)
885 int outtriangles = 0, outvertices = 0;
888 float ratio, direction[3], projectvector[3];
890 if (projectdirection)
891 VectorScale(projectdirection, projectdistance, projectvector);
893 VectorClear(projectvector);
895 // create the vertices
896 if (projectdirection)
898 for (i = 0;i < numshadowmarktris;i++)
900 element = inelement3i + shadowmarktris[i] * 3;
901 for (j = 0;j < 3;j++)
903 if (vertexupdate[element[j]] != vertexupdatenum)
905 vertexupdate[element[j]] = vertexupdatenum;
906 vertexremap[element[j]] = outvertices;
907 vertex = invertex3f + element[j] * 3;
908 // project one copy of the vertex according to projectvector
909 VectorCopy(vertex, outvertex3f);
910 VectorAdd(vertex, projectvector, (outvertex3f + 3));
919 for (i = 0;i < numshadowmarktris;i++)
921 element = inelement3i + shadowmarktris[i] * 3;
922 for (j = 0;j < 3;j++)
924 if (vertexupdate[element[j]] != vertexupdatenum)
926 vertexupdate[element[j]] = vertexupdatenum;
927 vertexremap[element[j]] = outvertices;
928 vertex = invertex3f + element[j] * 3;
929 // project one copy of the vertex to the sphere radius of the light
930 // (FIXME: would projecting it to the light box be better?)
931 VectorSubtract(vertex, projectorigin, direction);
932 ratio = projectdistance / VectorLength(direction);
933 VectorCopy(vertex, outvertex3f);
934 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
942 if (r_shadow_frontsidecasting.integer)
944 for (i = 0;i < numshadowmarktris;i++)
946 int remappedelement[3];
948 const int *neighbortriangle;
950 markindex = shadowmarktris[i] * 3;
951 element = inelement3i + markindex;
952 neighbortriangle = inneighbor3i + markindex;
953 // output the front and back triangles
954 outelement3i[0] = vertexremap[element[0]];
955 outelement3i[1] = vertexremap[element[1]];
956 outelement3i[2] = vertexremap[element[2]];
957 outelement3i[3] = vertexremap[element[2]] + 1;
958 outelement3i[4] = vertexremap[element[1]] + 1;
959 outelement3i[5] = vertexremap[element[0]] + 1;
963 // output the sides (facing outward from this triangle)
964 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
966 remappedelement[0] = vertexremap[element[0]];
967 remappedelement[1] = vertexremap[element[1]];
968 outelement3i[0] = remappedelement[1];
969 outelement3i[1] = remappedelement[0];
970 outelement3i[2] = remappedelement[0] + 1;
971 outelement3i[3] = remappedelement[1];
972 outelement3i[4] = remappedelement[0] + 1;
973 outelement3i[5] = remappedelement[1] + 1;
978 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
980 remappedelement[1] = vertexremap[element[1]];
981 remappedelement[2] = vertexremap[element[2]];
982 outelement3i[0] = remappedelement[2];
983 outelement3i[1] = remappedelement[1];
984 outelement3i[2] = remappedelement[1] + 1;
985 outelement3i[3] = remappedelement[2];
986 outelement3i[4] = remappedelement[1] + 1;
987 outelement3i[5] = remappedelement[2] + 1;
992 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
994 remappedelement[0] = vertexremap[element[0]];
995 remappedelement[2] = vertexremap[element[2]];
996 outelement3i[0] = remappedelement[0];
997 outelement3i[1] = remappedelement[2];
998 outelement3i[2] = remappedelement[2] + 1;
999 outelement3i[3] = remappedelement[0];
1000 outelement3i[4] = remappedelement[2] + 1;
1001 outelement3i[5] = remappedelement[0] + 1;
1010 for (i = 0;i < numshadowmarktris;i++)
1012 int remappedelement[3];
1014 const int *neighbortriangle;
1016 markindex = shadowmarktris[i] * 3;
1017 element = inelement3i + markindex;
1018 neighbortriangle = inneighbor3i + markindex;
1019 // output the front and back triangles
1020 outelement3i[0] = vertexremap[element[2]];
1021 outelement3i[1] = vertexremap[element[1]];
1022 outelement3i[2] = vertexremap[element[0]];
1023 outelement3i[3] = vertexremap[element[0]] + 1;
1024 outelement3i[4] = vertexremap[element[1]] + 1;
1025 outelement3i[5] = vertexremap[element[2]] + 1;
1029 // output the sides (facing outward from this triangle)
1030 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1032 remappedelement[0] = vertexremap[element[0]];
1033 remappedelement[1] = vertexremap[element[1]];
1034 outelement3i[0] = remappedelement[0];
1035 outelement3i[1] = remappedelement[1];
1036 outelement3i[2] = remappedelement[1] + 1;
1037 outelement3i[3] = remappedelement[0];
1038 outelement3i[4] = remappedelement[1] + 1;
1039 outelement3i[5] = remappedelement[0] + 1;
1044 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1046 remappedelement[1] = vertexremap[element[1]];
1047 remappedelement[2] = vertexremap[element[2]];
1048 outelement3i[0] = remappedelement[1];
1049 outelement3i[1] = remappedelement[2];
1050 outelement3i[2] = remappedelement[2] + 1;
1051 outelement3i[3] = remappedelement[1];
1052 outelement3i[4] = remappedelement[2] + 1;
1053 outelement3i[5] = remappedelement[1] + 1;
1058 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1060 remappedelement[0] = vertexremap[element[0]];
1061 remappedelement[2] = vertexremap[element[2]];
1062 outelement3i[0] = remappedelement[2];
1063 outelement3i[1] = remappedelement[0];
1064 outelement3i[2] = remappedelement[0] + 1;
1065 outelement3i[3] = remappedelement[2];
1066 outelement3i[4] = remappedelement[0] + 1;
1067 outelement3i[5] = remappedelement[2] + 1;
1075 *outnumvertices = outvertices;
1076 return outtriangles;
1079 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)
1082 int outtriangles = 0, outvertices = 0;
1084 const float *vertex;
1085 float ratio, direction[3], projectvector[3];
1088 if (projectdirection)
1089 VectorScale(projectdirection, projectdistance, projectvector);
1091 VectorClear(projectvector);
1093 for (i = 0;i < numshadowmarktris;i++)
1095 int remappedelement[3];
1097 const int *neighbortriangle;
1099 markindex = shadowmarktris[i] * 3;
1100 neighbortriangle = inneighbor3i + markindex;
1101 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1102 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1103 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1104 if (side[0] + side[1] + side[2] == 0)
1108 element = inelement3i + markindex;
1110 // create the vertices
1111 for (j = 0;j < 3;j++)
1113 if (side[j] + side[j+1] == 0)
1116 if (vertexupdate[k] != vertexupdatenum)
1118 vertexupdate[k] = vertexupdatenum;
1119 vertexremap[k] = outvertices;
1120 vertex = invertex3f + k * 3;
1121 VectorCopy(vertex, outvertex3f);
1122 if (projectdirection)
1124 // project one copy of the vertex according to projectvector
1125 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1129 // project one copy of the vertex to the sphere radius of the light
1130 // (FIXME: would projecting it to the light box be better?)
1131 VectorSubtract(vertex, projectorigin, direction);
1132 ratio = projectdistance / VectorLength(direction);
1133 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1140 // output the sides (facing outward from this triangle)
1143 remappedelement[0] = vertexremap[element[0]];
1144 remappedelement[1] = vertexremap[element[1]];
1145 outelement3i[0] = remappedelement[1];
1146 outelement3i[1] = remappedelement[0];
1147 outelement3i[2] = remappedelement[0] + 1;
1148 outelement3i[3] = remappedelement[1];
1149 outelement3i[4] = remappedelement[0] + 1;
1150 outelement3i[5] = remappedelement[1] + 1;
1157 remappedelement[1] = vertexremap[element[1]];
1158 remappedelement[2] = vertexremap[element[2]];
1159 outelement3i[0] = remappedelement[2];
1160 outelement3i[1] = remappedelement[1];
1161 outelement3i[2] = remappedelement[1] + 1;
1162 outelement3i[3] = remappedelement[2];
1163 outelement3i[4] = remappedelement[1] + 1;
1164 outelement3i[5] = remappedelement[2] + 1;
1171 remappedelement[0] = vertexremap[element[0]];
1172 remappedelement[2] = vertexremap[element[2]];
1173 outelement3i[0] = remappedelement[0];
1174 outelement3i[1] = remappedelement[2];
1175 outelement3i[2] = remappedelement[2] + 1;
1176 outelement3i[3] = remappedelement[0];
1177 outelement3i[4] = remappedelement[2] + 1;
1178 outelement3i[5] = remappedelement[0] + 1;
1185 *outnumvertices = outvertices;
1186 return outtriangles;
1189 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)
1195 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1197 tend = firsttriangle + numtris;
1198 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1200 // surface box entirely inside light box, no box cull
1201 if (projectdirection)
1203 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1205 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1206 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1207 shadowmarklist[numshadowmark++] = t;
1212 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1213 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1214 shadowmarklist[numshadowmark++] = t;
1219 // surface box not entirely inside light box, cull each triangle
1220 if (projectdirection)
1222 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1224 v[0] = invertex3f + e[0] * 3;
1225 v[1] = invertex3f + e[1] * 3;
1226 v[2] = invertex3f + e[2] * 3;
1227 TriangleNormal(v[0], v[1], v[2], normal);
1228 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1229 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1230 shadowmarklist[numshadowmark++] = t;
1235 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1237 v[0] = invertex3f + e[0] * 3;
1238 v[1] = invertex3f + e[1] * 3;
1239 v[2] = invertex3f + e[2] * 3;
1240 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1241 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1242 shadowmarklist[numshadowmark++] = t;
1248 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1253 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1255 // check if the shadow volume intersects the near plane
1257 // a ray between the eye and light origin may intersect the caster,
1258 // indicating that the shadow may touch the eye location, however we must
1259 // test the near plane (a polygon), not merely the eye location, so it is
1260 // easiest to enlarge the caster bounding shape slightly for this.
1266 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)
1268 int i, tris, outverts;
1269 if (projectdistance < 0.1)
1271 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1274 if (!numverts || !nummarktris)
1276 // make sure shadowelements is big enough for this volume
1277 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1278 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1280 if (maxvertexupdate < numverts)
1282 maxvertexupdate = numverts;
1284 Mem_Free(vertexupdate);
1286 Mem_Free(vertexremap);
1287 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1288 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1289 vertexupdatenum = 0;
1292 if (vertexupdatenum == 0)
1294 vertexupdatenum = 1;
1295 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1296 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1299 for (i = 0;i < nummarktris;i++)
1300 shadowmark[marktris[i]] = shadowmarkcount;
1302 if (r_shadow_compilingrtlight)
1304 // if we're compiling an rtlight, capture the mesh
1305 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1306 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1307 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1312 // decide which type of shadow to generate and set stencil mode
1313 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1314 // generate the sides or a solid volume, depending on type
1315 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1316 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1318 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1319 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1320 r_refdef.stats.lights_shadowtriangles += tris;
1322 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1323 GL_LockArrays(0, outverts);
1324 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1326 // increment stencil if frontface is infront of depthbuffer
1327 GL_CullFace(r_refdef.view.cullface_front);
1328 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1329 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1330 // decrement stencil if backface is infront of depthbuffer
1331 GL_CullFace(r_refdef.view.cullface_back);
1332 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1334 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1336 // decrement stencil if backface is behind depthbuffer
1337 GL_CullFace(r_refdef.view.cullface_front);
1338 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1339 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1340 // increment stencil if frontface is behind depthbuffer
1341 GL_CullFace(r_refdef.view.cullface_back);
1342 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1344 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1345 GL_LockArrays(0, 0);
1350 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1352 // p1, p2, p3 are in the cubemap's local coordinate system
1353 // bias = border/(size - border)
1356 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1357 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1358 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1359 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1361 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1362 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1363 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1364 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1366 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1367 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1368 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1370 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1371 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1372 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1373 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1375 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1376 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1377 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1378 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1380 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1381 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1382 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1384 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1385 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1386 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1387 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1389 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1390 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1391 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1392 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1394 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1395 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1396 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1401 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1403 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1404 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1407 VectorSubtract(maxs, mins, radius);
1408 VectorScale(radius, 0.5f, radius);
1409 VectorAdd(mins, radius, center);
1410 Matrix4x4_Transform(worldtolight, center, lightcenter);
1411 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1412 VectorSubtract(lightcenter, lightradius, pmin);
1413 VectorAdd(lightcenter, lightradius, pmax);
1415 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1416 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1417 if(ap1 > bias*an1 && ap2 > bias*an2)
1419 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1420 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1421 if(an1 > bias*ap1 && an2 > bias*ap2)
1423 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1424 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1426 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1427 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1428 if(ap1 > bias*an1 && ap2 > bias*an2)
1430 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1431 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1432 if(an1 > bias*ap1 && an2 > bias*ap2)
1434 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1435 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1437 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1438 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1439 if(ap1 > bias*an1 && ap2 > bias*an2)
1441 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1442 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1443 if(an1 > bias*ap1 && an2 > bias*ap2)
1445 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1446 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1451 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1453 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1455 // p is in the cubemap's local coordinate system
1456 // bias = border/(size - border)
1457 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1458 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1459 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1461 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1462 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1463 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1464 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1465 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1466 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1470 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1474 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1475 float scale = (size - 2*border)/size, len;
1476 float bias = border / (float)(size - border), dp, dn, ap, an;
1477 // check if cone enclosing side would cross frustum plane
1478 scale = 2 / (scale*scale + 2);
1479 for (i = 0;i < 5;i++)
1481 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1483 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1484 len = scale*VectorLength2(n);
1485 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1486 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1487 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1489 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1491 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1492 len = scale*VectorLength(n);
1493 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1494 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1495 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1497 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1498 // check if frustum corners/origin cross plane sides
1499 for (i = 0;i < 5;i++)
1501 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1502 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1503 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1504 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1505 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1506 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1507 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1508 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1509 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1510 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1512 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1515 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)
1523 int mask, surfacemask = 0;
1524 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1526 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1527 tend = firsttriangle + numtris;
1528 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1530 // surface box entirely inside light box, no box cull
1531 if (projectdirection)
1533 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1535 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1536 TriangleNormal(v[0], v[1], v[2], normal);
1537 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1539 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1540 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1541 surfacemask |= mask;
1544 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;
1545 shadowsides[numshadowsides] = mask;
1546 shadowsideslist[numshadowsides++] = t;
1553 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1555 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1556 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1558 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1559 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1560 surfacemask |= mask;
1563 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;
1564 shadowsides[numshadowsides] = mask;
1565 shadowsideslist[numshadowsides++] = t;
1573 // surface box not entirely inside light box, cull each triangle
1574 if (projectdirection)
1576 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1578 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1579 TriangleNormal(v[0], v[1], v[2], normal);
1580 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1581 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1583 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1584 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1585 surfacemask |= mask;
1588 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;
1589 shadowsides[numshadowsides] = mask;
1590 shadowsideslist[numshadowsides++] = t;
1597 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1599 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1600 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1601 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1603 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1604 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1605 surfacemask |= mask;
1608 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;
1609 shadowsides[numshadowsides] = mask;
1610 shadowsideslist[numshadowsides++] = t;
1619 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)
1621 int i, j, outtriangles = 0;
1622 int *outelement3i[6];
1623 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1625 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1626 // make sure shadowelements is big enough for this mesh
1627 if (maxshadowtriangles < outtriangles)
1628 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1630 // compute the offset and size of the separate index lists for each cubemap side
1632 for (i = 0;i < 6;i++)
1634 outelement3i[i] = shadowelements + outtriangles * 3;
1635 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1636 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1637 outtriangles += sidetotals[i];
1640 // gather up the (sparse) triangles into separate index lists for each cubemap side
1641 for (i = 0;i < numsidetris;i++)
1643 const int *element = elements + sidetris[i] * 3;
1644 for (j = 0;j < 6;j++)
1646 if (sides[i] & (1 << j))
1648 outelement3i[j][0] = element[0];
1649 outelement3i[j][1] = element[1];
1650 outelement3i[j][2] = element[2];
1651 outelement3i[j] += 3;
1656 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1659 static void R_Shadow_MakeTextures_MakeCorona(void)
1663 unsigned char pixels[32][32][4];
1664 for (y = 0;y < 32;y++)
1666 dy = (y - 15.5f) * (1.0f / 16.0f);
1667 for (x = 0;x < 32;x++)
1669 dx = (x - 15.5f) * (1.0f / 16.0f);
1670 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1671 a = bound(0, a, 255);
1672 pixels[y][x][0] = a;
1673 pixels[y][x][1] = a;
1674 pixels[y][x][2] = a;
1675 pixels[y][x][3] = 255;
1678 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1681 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1683 float dist = sqrt(x*x+y*y+z*z);
1684 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1685 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1686 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1689 static void R_Shadow_MakeTextures(void)
1692 float intensity, dist;
1694 R_FreeTexturePool(&r_shadow_texturepool);
1695 r_shadow_texturepool = R_AllocTexturePool();
1696 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1697 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1698 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1699 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1700 for (x = 0;x <= ATTENTABLESIZE;x++)
1702 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1703 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1704 r_shadow_attentable[x] = bound(0, intensity, 1);
1706 // 1D gradient texture
1707 for (x = 0;x < ATTEN1DSIZE;x++)
1708 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1709 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);
1710 // 2D circle texture
1711 for (y = 0;y < ATTEN2DSIZE;y++)
1712 for (x = 0;x < ATTEN2DSIZE;x++)
1713 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);
1714 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);
1715 // 3D sphere texture
1716 if (r_shadow_texture3d.integer && gl_texture3d)
1718 for (z = 0;z < ATTEN3DSIZE;z++)
1719 for (y = 0;y < ATTEN3DSIZE;y++)
1720 for (x = 0;x < ATTEN3DSIZE;x++)
1721 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));
1722 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);
1725 r_shadow_attenuation3dtexture = NULL;
1728 R_Shadow_MakeTextures_MakeCorona();
1730 // Editor light sprites
1731 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1732 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1733 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1734 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1735 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1736 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1739 void R_Shadow_ValidateCvars(void)
1741 if (r_shadow_texture3d.integer && !gl_texture3d)
1742 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1743 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1744 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1745 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1746 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1749 void R_Shadow_RenderMode_Begin(void)
1755 R_Shadow_ValidateCvars();
1757 if (!r_shadow_attenuation2dtexture
1758 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1759 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1760 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1761 R_Shadow_MakeTextures();
1764 R_Mesh_ColorPointer(NULL, 0, 0);
1765 R_Mesh_ResetTextureState();
1766 GL_BlendFunc(GL_ONE, GL_ZERO);
1767 GL_DepthRange(0, 1);
1768 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1770 GL_DepthMask(false);
1771 GL_Color(0, 0, 0, 1);
1772 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1774 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1776 if (gl_ext_separatestencil.integer)
1778 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1779 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1781 else if (gl_ext_stenciltwoside.integer)
1783 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1784 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1788 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1789 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1792 if (r_glsl.integer && gl_support_fragment_shader)
1793 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1794 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1795 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1797 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1801 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1802 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1803 r_shadow_drawbuffer = drawbuffer;
1804 r_shadow_readbuffer = readbuffer;
1806 r_shadow_cullface_front = r_refdef.view.cullface_front;
1807 r_shadow_cullface_back = r_refdef.view.cullface_back;
1810 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1812 rsurface.rtlight = rtlight;
1815 void R_Shadow_RenderMode_Reset(void)
1818 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1820 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1822 if (gl_support_ext_framebuffer_object)
1824 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1827 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1828 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1830 R_SetViewport(&r_refdef.view.viewport);
1831 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1832 R_Mesh_ColorPointer(NULL, 0, 0);
1833 R_Mesh_ResetTextureState();
1834 GL_DepthRange(0, 1);
1836 GL_DepthMask(false);
1837 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1838 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1839 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1840 qglStencilMask(~0);CHECKGLERROR
1841 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1842 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1843 r_refdef.view.cullface_front = r_shadow_cullface_front;
1844 r_refdef.view.cullface_back = r_shadow_cullface_back;
1845 GL_CullFace(r_refdef.view.cullface_back);
1846 GL_Color(1, 1, 1, 1);
1847 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1848 GL_BlendFunc(GL_ONE, GL_ZERO);
1849 R_SetupGenericShader(false);
1850 r_shadow_usingshadowmaprect = false;
1851 r_shadow_usingshadowmapcube = false;
1852 r_shadow_usingshadowmap2d = false;
1856 void R_Shadow_ClearStencil(void)
1859 GL_Clear(GL_STENCIL_BUFFER_BIT);
1860 r_refdef.stats.lights_clears++;
1863 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1865 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1866 if (r_shadow_rendermode == mode)
1869 R_Shadow_RenderMode_Reset();
1870 GL_ColorMask(0, 0, 0, 0);
1871 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1872 R_SetupDepthOrShadowShader();
1873 qglDepthFunc(GL_LESS);CHECKGLERROR
1874 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1875 r_shadow_rendermode = mode;
1880 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1881 GL_CullFace(GL_NONE);
1882 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1883 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1885 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1886 GL_CullFace(GL_NONE);
1887 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1888 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1890 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1891 GL_CullFace(GL_NONE);
1892 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1893 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1894 qglStencilMask(~0);CHECKGLERROR
1895 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1896 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1897 qglStencilMask(~0);CHECKGLERROR
1898 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1900 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1901 GL_CullFace(GL_NONE);
1902 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1903 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1904 qglStencilMask(~0);CHECKGLERROR
1905 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1906 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1907 qglStencilMask(~0);CHECKGLERROR
1908 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1913 static void R_Shadow_MakeVSDCT(void)
1915 // maps to a 2x3 texture rectangle with normalized coordinates
1920 // stores abs(dir.xy), offset.xy/2.5
1921 unsigned char data[4*6] =
1923 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1924 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1925 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1926 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1927 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1928 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1930 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1933 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1937 float nearclip, farclip, bias;
1938 r_viewport_t viewport;
1941 maxsize = r_shadow_shadowmapmaxsize;
1942 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1944 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1945 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1946 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1947 r_shadow_shadowmapside = side;
1948 r_shadow_shadowmapsize = size;
1949 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1951 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1952 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1953 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1954 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1956 // complex unrolled cube approach (more flexible)
1957 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1958 R_Shadow_MakeVSDCT();
1959 if (!r_shadow_shadowmap2dtexture)
1962 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1963 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1964 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1965 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1966 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1967 // render depth into the fbo, do not render color at all
1968 qglDrawBuffer(GL_NONE);CHECKGLERROR
1969 qglReadBuffer(GL_NONE);CHECKGLERROR
1970 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1971 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1973 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1974 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1979 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1980 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1981 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1982 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1984 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1986 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1987 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1988 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1989 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1991 // complex unrolled cube approach (more flexible)
1992 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1993 R_Shadow_MakeVSDCT();
1994 if (!r_shadow_shadowmaprectangletexture)
1997 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1998 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1999 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2000 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2001 // render depth into the fbo, do not render color at all
2002 qglDrawBuffer(GL_NONE);CHECKGLERROR
2003 qglReadBuffer(GL_NONE);CHECKGLERROR
2004 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2005 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2007 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2008 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2013 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2014 r_shadow_shadowmap_texturescale[0] = 1.0f;
2015 r_shadow_shadowmap_texturescale[1] = 1.0f;
2016 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2018 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2020 r_shadow_shadowmap_parameters[0] = 1.0f;
2021 r_shadow_shadowmap_parameters[1] = 1.0f;
2022 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2023 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2025 // simple cube approach
2026 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2029 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
2030 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2031 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2032 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
2033 // render depth into the fbo, do not render color at all
2034 qglDrawBuffer(GL_NONE);CHECKGLERROR
2035 qglReadBuffer(GL_NONE);CHECKGLERROR
2036 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2037 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2039 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2040 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2045 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2046 r_shadow_shadowmap_texturescale[0] = 0.0f;
2047 r_shadow_shadowmap_texturescale[1] = 0.0f;
2048 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2051 R_Shadow_RenderMode_Reset();
2054 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2055 R_SetupDepthOrShadowShader();
2059 R_SetupShowDepthShader();
2060 qglClearColor(1,1,1,1);CHECKGLERROR
2063 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2070 R_SetViewport(&viewport);
2071 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2072 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2074 int flipped = (side&1)^(side>>2);
2075 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2076 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2077 GL_CullFace(r_refdef.view.cullface_back);
2079 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2081 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
2084 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2088 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2091 R_Shadow_RenderMode_Reset();
2092 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2095 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2099 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2100 // only draw light where this geometry was already rendered AND the
2101 // stencil is 128 (values other than this mean shadow)
2102 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2104 r_shadow_rendermode = r_shadow_lightingrendermode;
2105 // do global setup needed for the chosen lighting mode
2106 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2108 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2109 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2113 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2115 r_shadow_usingshadowmap2d = true;
2116 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2119 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2121 r_shadow_usingshadowmaprect = true;
2122 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2125 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2127 r_shadow_usingshadowmapcube = true;
2128 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2132 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2134 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2139 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2140 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2141 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2145 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2148 R_Shadow_RenderMode_Reset();
2149 GL_BlendFunc(GL_ONE, GL_ONE);
2150 GL_DepthRange(0, 1);
2151 GL_DepthTest(r_showshadowvolumes.integer < 2);
2152 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2153 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2154 GL_CullFace(GL_NONE);
2155 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2158 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2161 R_Shadow_RenderMode_Reset();
2162 GL_BlendFunc(GL_ONE, GL_ONE);
2163 GL_DepthRange(0, 1);
2164 GL_DepthTest(r_showlighting.integer < 2);
2165 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2168 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2172 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2173 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2175 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2178 void R_Shadow_RenderMode_End(void)
2181 R_Shadow_RenderMode_Reset();
2182 R_Shadow_RenderMode_ActiveLight(NULL);
2184 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2185 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2188 int bboxedges[12][2] =
2207 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2209 int i, ix1, iy1, ix2, iy2;
2210 float x1, y1, x2, y2;
2212 float vertex[20][3];
2221 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2222 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2223 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2224 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2226 if (!r_shadow_scissor.integer)
2229 // if view is inside the light box, just say yes it's visible
2230 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2233 x1 = y1 = x2 = y2 = 0;
2235 // transform all corners that are infront of the nearclip plane
2236 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2237 plane4f[3] = r_refdef.view.frustum[4].dist;
2239 for (i = 0;i < 8;i++)
2241 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2242 dist[i] = DotProduct4(corner[i], plane4f);
2243 sign[i] = dist[i] > 0;
2246 VectorCopy(corner[i], vertex[numvertices]);
2250 // if some points are behind the nearclip, add clipped edge points to make
2251 // sure that the scissor boundary is complete
2252 if (numvertices > 0 && numvertices < 8)
2254 // add clipped edge points
2255 for (i = 0;i < 12;i++)
2257 j = bboxedges[i][0];
2258 k = bboxedges[i][1];
2259 if (sign[j] != sign[k])
2261 f = dist[j] / (dist[j] - dist[k]);
2262 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2268 // if we have no points to check, the light is behind the view plane
2272 // if we have some points to transform, check what screen area is covered
2273 x1 = y1 = x2 = y2 = 0;
2275 //Con_Printf("%i vertices to transform...\n", numvertices);
2276 for (i = 0;i < numvertices;i++)
2278 VectorCopy(vertex[i], v);
2279 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2280 //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]);
2283 if (x1 > v2[0]) x1 = v2[0];
2284 if (x2 < v2[0]) x2 = v2[0];
2285 if (y1 > v2[1]) y1 = v2[1];
2286 if (y2 < v2[1]) y2 = v2[1];
2295 // now convert the scissor rectangle to integer screen coordinates
2296 ix1 = (int)(x1 - 1.0f);
2297 iy1 = vid.height - (int)(y2 - 1.0f);
2298 ix2 = (int)(x2 + 1.0f);
2299 iy2 = vid.height - (int)(y1 + 1.0f);
2300 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2302 // clamp it to the screen
2303 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2304 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2305 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2306 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2308 // if it is inside out, it's not visible
2309 if (ix2 <= ix1 || iy2 <= iy1)
2312 // the light area is visible, set up the scissor rectangle
2313 r_shadow_lightscissor[0] = ix1;
2314 r_shadow_lightscissor[1] = iy1;
2315 r_shadow_lightscissor[2] = ix2 - ix1;
2316 r_shadow_lightscissor[3] = iy2 - iy1;
2318 r_refdef.stats.lights_scissored++;
2322 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2324 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2325 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2326 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2327 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2328 if (r_textureunits.integer >= 3)
2330 if (VectorLength2(diffusecolor) > 0)
2332 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2334 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2335 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2336 if ((dot = DotProduct(n, v)) < 0)
2338 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2339 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2342 VectorCopy(ambientcolor, color4f);
2343 if (r_refdef.fogenabled)
2346 f = FogPoint_Model(vertex3f);
2347 VectorScale(color4f, f, color4f);
2354 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2356 VectorCopy(ambientcolor, color4f);
2357 if (r_refdef.fogenabled)
2360 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2361 f = FogPoint_Model(vertex3f);
2362 VectorScale(color4f, f, color4f);
2368 else if (r_textureunits.integer >= 2)
2370 if (VectorLength2(diffusecolor) > 0)
2372 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2374 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2375 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2377 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2378 if ((dot = DotProduct(n, v)) < 0)
2380 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2381 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2382 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2383 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2387 color4f[0] = ambientcolor[0] * distintensity;
2388 color4f[1] = ambientcolor[1] * distintensity;
2389 color4f[2] = ambientcolor[2] * distintensity;
2391 if (r_refdef.fogenabled)
2394 f = FogPoint_Model(vertex3f);
2395 VectorScale(color4f, f, color4f);
2399 VectorClear(color4f);
2405 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2407 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2408 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2410 color4f[0] = ambientcolor[0] * distintensity;
2411 color4f[1] = ambientcolor[1] * distintensity;
2412 color4f[2] = ambientcolor[2] * distintensity;
2413 if (r_refdef.fogenabled)
2416 f = FogPoint_Model(vertex3f);
2417 VectorScale(color4f, f, color4f);
2421 VectorClear(color4f);
2428 if (VectorLength2(diffusecolor) > 0)
2430 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2432 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2433 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2435 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2436 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2437 if ((dot = DotProduct(n, v)) < 0)
2439 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2440 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2441 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2442 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2446 color4f[0] = ambientcolor[0] * distintensity;
2447 color4f[1] = ambientcolor[1] * distintensity;
2448 color4f[2] = ambientcolor[2] * distintensity;
2450 if (r_refdef.fogenabled)
2453 f = FogPoint_Model(vertex3f);
2454 VectorScale(color4f, f, color4f);
2458 VectorClear(color4f);
2464 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2466 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2467 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2469 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2470 color4f[0] = ambientcolor[0] * distintensity;
2471 color4f[1] = ambientcolor[1] * distintensity;
2472 color4f[2] = ambientcolor[2] * distintensity;
2473 if (r_refdef.fogenabled)
2476 f = FogPoint_Model(vertex3f);
2477 VectorScale(color4f, f, color4f);
2481 VectorClear(color4f);
2488 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2490 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2493 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2494 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2495 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2496 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2497 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2499 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2501 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2502 // the cubemap normalizes this for us
2503 out3f[0] = DotProduct(svector3f, lightdir);
2504 out3f[1] = DotProduct(tvector3f, lightdir);
2505 out3f[2] = DotProduct(normal3f, lightdir);
2509 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2512 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2513 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2514 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2515 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2516 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2517 float lightdir[3], eyedir[3], halfdir[3];
2518 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2520 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2521 VectorNormalize(lightdir);
2522 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2523 VectorNormalize(eyedir);
2524 VectorAdd(lightdir, eyedir, halfdir);
2525 // the cubemap normalizes this for us
2526 out3f[0] = DotProduct(svector3f, halfdir);
2527 out3f[1] = DotProduct(tvector3f, halfdir);
2528 out3f[2] = DotProduct(normal3f, halfdir);
2532 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)
2534 // used to display how many times a surface is lit for level design purposes
2535 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2538 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)
2540 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2541 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2542 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2543 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2545 R_Mesh_ColorPointer(NULL, 0, 0);
2546 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2547 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2548 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2549 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2550 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2551 if (rsurface.texture->backgroundcurrentskinframe)
2553 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2554 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2555 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2556 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2558 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2559 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2560 if(rsurface.texture->colormapping)
2562 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2563 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2565 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2566 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2567 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2568 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2569 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2570 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2572 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2574 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2575 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2577 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2581 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)
2583 // shared final code for all the dot3 layers
2585 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2586 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2588 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2589 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2593 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)
2596 // colorscale accounts for how much we multiply the brightness
2599 // mult is how many times the final pass of the lighting will be
2600 // performed to get more brightness than otherwise possible.
2602 // Limit mult to 64 for sanity sake.
2604 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2606 // 3 3D combine path (Geforce3, Radeon 8500)
2607 memset(&m, 0, sizeof(m));
2608 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2609 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2610 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2611 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2612 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2613 m.tex[1] = R_GetTexture(basetexture);
2614 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2615 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2616 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2617 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2618 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2619 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2620 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2621 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2622 m.texmatrix[2] = rsurface.entitytolight;
2623 GL_BlendFunc(GL_ONE, GL_ONE);
2625 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2627 // 2 3D combine path (Geforce3, original Radeon)
2628 memset(&m, 0, sizeof(m));
2629 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2630 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2631 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2632 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2633 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2634 m.tex[1] = R_GetTexture(basetexture);
2635 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2636 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2637 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2638 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2639 GL_BlendFunc(GL_ONE, GL_ONE);
2641 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2643 // 4 2D combine path (Geforce3, Radeon 8500)
2644 memset(&m, 0, sizeof(m));
2645 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2646 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2647 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2648 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2649 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2650 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2651 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2652 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2653 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2654 m.texmatrix[1] = rsurface.entitytoattenuationz;
2655 m.tex[2] = R_GetTexture(basetexture);
2656 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2657 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2658 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2659 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2660 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2662 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2663 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2664 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2665 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2666 m.texmatrix[3] = rsurface.entitytolight;
2668 GL_BlendFunc(GL_ONE, GL_ONE);
2670 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2672 // 3 2D combine path (Geforce3, original Radeon)
2673 memset(&m, 0, sizeof(m));
2674 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2675 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2676 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2677 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2678 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2679 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2680 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2681 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2682 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2683 m.texmatrix[1] = rsurface.entitytoattenuationz;
2684 m.tex[2] = R_GetTexture(basetexture);
2685 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2686 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2687 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2688 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2689 GL_BlendFunc(GL_ONE, GL_ONE);
2693 // 2/2/2 2D combine path (any dot3 card)
2694 memset(&m, 0, sizeof(m));
2695 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2696 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2697 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2698 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2699 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2700 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2701 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2702 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2703 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2704 m.texmatrix[1] = rsurface.entitytoattenuationz;
2705 R_Mesh_TextureState(&m);
2706 GL_ColorMask(0,0,0,1);
2707 GL_BlendFunc(GL_ONE, GL_ZERO);
2708 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2711 memset(&m, 0, sizeof(m));
2712 m.tex[0] = R_GetTexture(basetexture);
2713 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2714 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2715 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2716 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2717 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2719 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2720 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2721 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2722 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2723 m.texmatrix[1] = rsurface.entitytolight;
2725 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2727 // this final code is shared
2728 R_Mesh_TextureState(&m);
2729 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);
2732 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)
2735 // colorscale accounts for how much we multiply the brightness
2738 // mult is how many times the final pass of the lighting will be
2739 // performed to get more brightness than otherwise possible.
2741 // Limit mult to 64 for sanity sake.
2743 // generate normalization cubemap texcoords
2744 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2745 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2747 // 3/2 3D combine path (Geforce3, Radeon 8500)
2748 memset(&m, 0, sizeof(m));
2749 m.tex[0] = R_GetTexture(normalmaptexture);
2750 m.texcombinergb[0] = GL_REPLACE;
2751 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2752 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2753 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2754 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2755 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2756 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2757 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2758 m.pointer_texcoord_bufferobject[1] = 0;
2759 m.pointer_texcoord_bufferoffset[1] = 0;
2760 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2761 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2762 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2763 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2764 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2765 R_Mesh_TextureState(&m);
2766 GL_ColorMask(0,0,0,1);
2767 GL_BlendFunc(GL_ONE, GL_ZERO);
2768 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2771 memset(&m, 0, sizeof(m));
2772 m.tex[0] = R_GetTexture(basetexture);
2773 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2774 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2775 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2776 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2777 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2779 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2780 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2781 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2782 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2783 m.texmatrix[1] = rsurface.entitytolight;
2785 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2787 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2789 // 1/2/2 3D combine path (original Radeon)
2790 memset(&m, 0, sizeof(m));
2791 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2792 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2793 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2794 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2795 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2796 R_Mesh_TextureState(&m);
2797 GL_ColorMask(0,0,0,1);
2798 GL_BlendFunc(GL_ONE, GL_ZERO);
2799 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2802 memset(&m, 0, sizeof(m));
2803 m.tex[0] = R_GetTexture(normalmaptexture);
2804 m.texcombinergb[0] = GL_REPLACE;
2805 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2806 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2807 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2808 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2809 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2810 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2811 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2812 m.pointer_texcoord_bufferobject[1] = 0;
2813 m.pointer_texcoord_bufferoffset[1] = 0;
2814 R_Mesh_TextureState(&m);
2815 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2816 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2819 memset(&m, 0, sizeof(m));
2820 m.tex[0] = R_GetTexture(basetexture);
2821 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2822 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2823 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2824 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2825 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2827 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2828 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2829 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2830 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2831 m.texmatrix[1] = rsurface.entitytolight;
2833 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2835 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2837 // 2/2 3D combine path (original Radeon)
2838 memset(&m, 0, sizeof(m));
2839 m.tex[0] = R_GetTexture(normalmaptexture);
2840 m.texcombinergb[0] = GL_REPLACE;
2841 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2842 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2843 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2844 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2845 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2846 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2847 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2848 m.pointer_texcoord_bufferobject[1] = 0;
2849 m.pointer_texcoord_bufferoffset[1] = 0;
2850 R_Mesh_TextureState(&m);
2851 GL_ColorMask(0,0,0,1);
2852 GL_BlendFunc(GL_ONE, GL_ZERO);
2853 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2856 memset(&m, 0, sizeof(m));
2857 m.tex[0] = R_GetTexture(basetexture);
2858 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2859 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2860 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2861 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2862 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2863 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2864 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2865 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2866 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2869 else if (r_textureunits.integer >= 4)
2871 // 4/2 2D combine path (Geforce3, Radeon 8500)
2872 memset(&m, 0, sizeof(m));
2873 m.tex[0] = R_GetTexture(normalmaptexture);
2874 m.texcombinergb[0] = GL_REPLACE;
2875 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2876 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2877 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2878 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2879 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2880 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2881 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2882 m.pointer_texcoord_bufferobject[1] = 0;
2883 m.pointer_texcoord_bufferoffset[1] = 0;
2884 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2885 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2886 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2887 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2888 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2889 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2890 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2891 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2892 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2893 m.texmatrix[3] = rsurface.entitytoattenuationz;
2894 R_Mesh_TextureState(&m);
2895 GL_ColorMask(0,0,0,1);
2896 GL_BlendFunc(GL_ONE, GL_ZERO);
2897 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2900 memset(&m, 0, sizeof(m));
2901 m.tex[0] = R_GetTexture(basetexture);
2902 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2903 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2904 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2905 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2906 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2908 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2909 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2910 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2911 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2912 m.texmatrix[1] = rsurface.entitytolight;
2914 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2918 // 2/2/2 2D combine path (any dot3 card)
2919 memset(&m, 0, sizeof(m));
2920 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2921 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2922 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2923 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2924 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2925 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2926 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2927 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2928 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2929 m.texmatrix[1] = rsurface.entitytoattenuationz;
2930 R_Mesh_TextureState(&m);
2931 GL_ColorMask(0,0,0,1);
2932 GL_BlendFunc(GL_ONE, GL_ZERO);
2933 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2936 memset(&m, 0, sizeof(m));
2937 m.tex[0] = R_GetTexture(normalmaptexture);
2938 m.texcombinergb[0] = GL_REPLACE;
2939 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2940 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2941 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2942 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2943 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2944 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2945 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2946 m.pointer_texcoord_bufferobject[1] = 0;
2947 m.pointer_texcoord_bufferoffset[1] = 0;
2948 R_Mesh_TextureState(&m);
2949 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2950 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2953 memset(&m, 0, sizeof(m));
2954 m.tex[0] = R_GetTexture(basetexture);
2955 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2956 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2957 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2958 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2959 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2961 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2962 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2963 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2964 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2965 m.texmatrix[1] = rsurface.entitytolight;
2967 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2969 // this final code is shared
2970 R_Mesh_TextureState(&m);
2971 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);
2974 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)
2976 float glossexponent;
2978 // FIXME: detect blendsquare!
2979 //if (!gl_support_blendsquare)
2982 // generate normalization cubemap texcoords
2983 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2984 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2986 // 2/0/0/1/2 3D combine blendsquare path
2987 memset(&m, 0, sizeof(m));
2988 m.tex[0] = R_GetTexture(normalmaptexture);
2989 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2990 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2991 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2992 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2993 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2994 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2995 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2996 m.pointer_texcoord_bufferobject[1] = 0;
2997 m.pointer_texcoord_bufferoffset[1] = 0;
2998 R_Mesh_TextureState(&m);
2999 GL_ColorMask(0,0,0,1);
3000 // this squares the result
3001 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3002 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3004 // second and third pass
3005 R_Mesh_ResetTextureState();
3006 // square alpha in framebuffer a few times to make it shiny
3007 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3008 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3009 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3012 memset(&m, 0, sizeof(m));
3013 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3014 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3015 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3016 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3017 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3018 R_Mesh_TextureState(&m);
3019 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3020 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3023 memset(&m, 0, sizeof(m));
3024 m.tex[0] = R_GetTexture(glosstexture);
3025 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3026 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3027 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3028 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3029 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3031 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3032 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3033 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3034 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3035 m.texmatrix[1] = rsurface.entitytolight;
3037 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3039 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3041 // 2/0/0/2 3D combine blendsquare path
3042 memset(&m, 0, sizeof(m));
3043 m.tex[0] = R_GetTexture(normalmaptexture);
3044 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3045 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3046 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3047 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3048 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3049 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3050 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3051 m.pointer_texcoord_bufferobject[1] = 0;
3052 m.pointer_texcoord_bufferoffset[1] = 0;
3053 R_Mesh_TextureState(&m);
3054 GL_ColorMask(0,0,0,1);
3055 // this squares the result
3056 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3057 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3059 // second and third pass
3060 R_Mesh_ResetTextureState();
3061 // square alpha in framebuffer a few times to make it shiny
3062 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3063 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3064 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3067 memset(&m, 0, sizeof(m));
3068 m.tex[0] = R_GetTexture(glosstexture);
3069 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3070 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3071 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3072 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3073 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3074 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3075 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3076 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3077 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3078 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3082 // 2/0/0/2/2 2D combine blendsquare path
3083 memset(&m, 0, sizeof(m));
3084 m.tex[0] = R_GetTexture(normalmaptexture);
3085 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3086 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3087 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3088 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3089 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3090 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3091 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3092 m.pointer_texcoord_bufferobject[1] = 0;
3093 m.pointer_texcoord_bufferoffset[1] = 0;
3094 R_Mesh_TextureState(&m);
3095 GL_ColorMask(0,0,0,1);
3096 // this squares the result
3097 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3098 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3100 // second and third pass
3101 R_Mesh_ResetTextureState();
3102 // square alpha in framebuffer a few times to make it shiny
3103 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3104 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3105 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3108 memset(&m, 0, sizeof(m));
3109 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3110 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3111 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3112 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3113 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3114 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3115 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3116 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3117 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3118 m.texmatrix[1] = rsurface.entitytoattenuationz;
3119 R_Mesh_TextureState(&m);
3120 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3121 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3124 memset(&m, 0, sizeof(m));
3125 m.tex[0] = R_GetTexture(glosstexture);
3126 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3127 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3128 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3129 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3130 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3132 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3133 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3134 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3135 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3136 m.texmatrix[1] = rsurface.entitytolight;
3138 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3140 // this final code is shared
3141 R_Mesh_TextureState(&m);
3142 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);
3145 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)
3147 // ARB path (any Geforce, any Radeon)
3148 qboolean doambient = ambientscale > 0;
3149 qboolean dodiffuse = diffusescale > 0;
3150 qboolean dospecular = specularscale > 0;
3151 if (!doambient && !dodiffuse && !dospecular)
3153 R_Mesh_ColorPointer(NULL, 0, 0);
3155 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3157 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3161 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3163 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3168 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3170 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3173 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3176 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3183 int newnumtriangles;
3187 int maxtriangles = 4096;
3188 int newelements[4096*3];
3189 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3190 for (renders = 0;renders < 64;renders++)
3195 newnumtriangles = 0;
3197 // due to low fillrate on the cards this vertex lighting path is
3198 // designed for, we manually cull all triangles that do not
3199 // contain a lit vertex
3200 // this builds batches of triangles from multiple surfaces and
3201 // renders them at once
3202 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3204 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3206 if (newnumtriangles)
3208 newfirstvertex = min(newfirstvertex, e[0]);
3209 newlastvertex = max(newlastvertex, e[0]);
3213 newfirstvertex = e[0];
3214 newlastvertex = e[0];
3216 newfirstvertex = min(newfirstvertex, e[1]);
3217 newlastvertex = max(newlastvertex, e[1]);
3218 newfirstvertex = min(newfirstvertex, e[2]);
3219 newlastvertex = max(newlastvertex, e[2]);
3225 if (newnumtriangles >= maxtriangles)
3227 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3228 newnumtriangles = 0;
3234 if (newnumtriangles >= 1)
3236 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3239 // if we couldn't find any lit triangles, exit early
3242 // now reduce the intensity for the next overbright pass
3243 // we have to clamp to 0 here incase the drivers have improper
3244 // handling of negative colors
3245 // (some old drivers even have improper handling of >1 color)
3247 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3249 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3251 c[0] = max(0, c[0] - 1);
3252 c[1] = max(0, c[1] - 1);
3253 c[2] = max(0, c[2] - 1);
3265 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)
3267 // OpenGL 1.1 path (anything)
3268 float ambientcolorbase[3], diffusecolorbase[3];
3269 float ambientcolorpants[3], diffusecolorpants[3];
3270 float ambientcolorshirt[3], diffusecolorshirt[3];
3272 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3273 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3274 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3275 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3276 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3277 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3278 memset(&m, 0, sizeof(m));
3279 m.tex[0] = R_GetTexture(basetexture);
3280 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3281 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3282 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3283 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3284 if (r_textureunits.integer >= 2)
3287 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3288 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3289 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3290 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3291 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3292 if (r_textureunits.integer >= 3)
3294 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3295 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3296 m.texmatrix[2] = rsurface.entitytoattenuationz;
3297 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3298 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3299 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3302 R_Mesh_TextureState(&m);
3303 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3304 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3307 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3308 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3312 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3313 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3317 extern cvar_t gl_lightmaps;
3318 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)
3320 float ambientscale, diffusescale, specularscale;
3321 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3323 // calculate colors to render this texture with
3324 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3325 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3326 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3327 ambientscale = rsurface.rtlight->ambientscale;
3328 diffusescale = rsurface.rtlight->diffusescale;
3329 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3330 if (!r_shadow_usenormalmap.integer)
3332 ambientscale += 1.0f * diffusescale;
3336 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3338 RSurf_SetupDepthAndCulling();
3339 nmap = rsurface.texture->currentskinframe->nmap;
3340 if (gl_lightmaps.integer)
3341 nmap = r_texture_blanknormalmap;
3342 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3344 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3345 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3348 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3349 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3350 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3353 VectorClear(lightcolorpants);
3356 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3357 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3358 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3361 VectorClear(lightcolorshirt);
3362 switch (r_shadow_rendermode)
3364 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3365 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3366 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);
3368 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3369 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);
3371 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3372 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);
3374 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3375 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);
3378 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3384 switch (r_shadow_rendermode)
3386 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3387 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3388 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);
3390 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3391 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);
3393 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3394 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);
3396 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3397 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);
3400 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3406 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)
3408 matrix4x4_t tempmatrix = *matrix;
3409 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3411 // if this light has been compiled before, free the associated data
3412 R_RTLight_Uncompile(rtlight);
3414 // clear it completely to avoid any lingering data
3415 memset(rtlight, 0, sizeof(*rtlight));
3417 // copy the properties
3418 rtlight->matrix_lighttoworld = tempmatrix;
3419 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3420 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3421 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3422 VectorCopy(color, rtlight->color);
3423 rtlight->cubemapname[0] = 0;
3424 if (cubemapname && cubemapname[0])
3425 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3426 rtlight->shadow = shadow;
3427 rtlight->corona = corona;
3428 rtlight->style = style;
3429 rtlight->isstatic = isstatic;
3430 rtlight->coronasizescale = coronasizescale;
3431 rtlight->ambientscale = ambientscale;
3432 rtlight->diffusescale = diffusescale;
3433 rtlight->specularscale = specularscale;
3434 rtlight->flags = flags;
3436 // compute derived data
3437 //rtlight->cullradius = rtlight->radius;
3438 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3439 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3440 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3441 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3442 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3443 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3444 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3447 // compiles rtlight geometry
3448 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3449 void R_RTLight_Compile(rtlight_t *rtlight)
3452 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3453 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3454 entity_render_t *ent = r_refdef.scene.worldentity;
3455 dp_model_t *model = r_refdef.scene.worldmodel;
3456 unsigned char *data;
3459 // compile the light
3460 rtlight->compiled = true;
3461 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3462 rtlight->static_numleafs = 0;
3463 rtlight->static_numleafpvsbytes = 0;
3464 rtlight->static_leaflist = NULL;
3465 rtlight->static_leafpvs = NULL;
3466 rtlight->static_numsurfaces = 0;
3467 rtlight->static_surfacelist = NULL;
3468 rtlight->static_shadowmap_receivers = 0x3F;
3469 rtlight->static_shadowmap_casters = 0x3F;
3470 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3471 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3472 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3473 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3474 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3475 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3477 if (model && model->GetLightInfo)
3479 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3480 r_shadow_compilingrtlight = rtlight;
3481 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);
3482 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);
3483 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3484 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3485 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3486 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3487 rtlight->static_numsurfaces = numsurfaces;
3488 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3489 rtlight->static_numleafs = numleafs;
3490 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3491 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3492 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3493 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3494 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3495 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3496 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3497 if (rtlight->static_numsurfaces)
3498 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3499 if (rtlight->static_numleafs)
3500 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3501 if (rtlight->static_numleafpvsbytes)
3502 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3503 if (rtlight->static_numshadowtrispvsbytes)
3504 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3505 if (rtlight->static_numlighttrispvsbytes)
3506 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3507 switch (rtlight->shadowmode)
3509 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3510 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3511 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3512 if (model->CompileShadowMap && rtlight->shadow)
3513 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3516 if (model->CompileShadowVolume && rtlight->shadow)
3517 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3520 // now we're done compiling the rtlight
3521 r_shadow_compilingrtlight = NULL;
3525 // use smallest available cullradius - box radius or light radius
3526 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3527 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3529 shadowzpasstris = 0;
3530 if (rtlight->static_meshchain_shadow_zpass)
3531 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3532 shadowzpasstris += mesh->numtriangles;
3534 shadowzfailtris = 0;
3535 if (rtlight->static_meshchain_shadow_zfail)
3536 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3537 shadowzfailtris += mesh->numtriangles;
3540 if (rtlight->static_numlighttrispvsbytes)
3541 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3542 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3546 if (rtlight->static_numlighttrispvsbytes)
3547 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3548 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3551 if (developer.integer >= 10)
3552 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);
3555 void R_RTLight_Uncompile(rtlight_t *rtlight)
3557 if (rtlight->compiled)
3559 if (rtlight->static_meshchain_shadow_zpass)
3560 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3561 rtlight->static_meshchain_shadow_zpass = NULL;
3562 if (rtlight->static_meshchain_shadow_zfail)
3563 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3564 rtlight->static_meshchain_shadow_zfail = NULL;
3565 if (rtlight->static_meshchain_shadow_shadowmap)
3566 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3567 rtlight->static_meshchain_shadow_shadowmap = NULL;
3568 // these allocations are grouped
3569 if (rtlight->static_surfacelist)
3570 Mem_Free(rtlight->static_surfacelist);
3571 rtlight->static_numleafs = 0;
3572 rtlight->static_numleafpvsbytes = 0;
3573 rtlight->static_leaflist = NULL;
3574 rtlight->static_leafpvs = NULL;
3575 rtlight->static_numsurfaces = 0;
3576 rtlight->static_surfacelist = NULL;
3577 rtlight->static_numshadowtrispvsbytes = 0;
3578 rtlight->static_shadowtrispvs = NULL;
3579 rtlight->static_numlighttrispvsbytes = 0;
3580 rtlight->static_lighttrispvs = NULL;
3581 rtlight->compiled = false;
3585 void R_Shadow_UncompileWorldLights(void)
3589 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3590 for (lightindex = 0;lightindex < range;lightindex++)
3592 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3595 R_RTLight_Uncompile(&light->rtlight);
3599 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3603 // reset the count of frustum planes
3604 // see rsurface.rtlight_frustumplanes definition for how much this array
3606 rsurface.rtlight_numfrustumplanes = 0;
3608 // haven't implemented a culling path for ortho rendering
3609 if (!r_refdef.view.useperspective)
3611 // check if the light is on screen and copy the 4 planes if it is
3612 for (i = 0;i < 4;i++)
3613 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3616 for (i = 0;i < 4;i++)
3617 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3622 // generate a deformed frustum that includes the light origin, this is
3623 // used to cull shadow casting surfaces that can not possibly cast a
3624 // shadow onto the visible light-receiving surfaces, which can be a
3627 // if the light origin is onscreen the result will be 4 planes exactly
3628 // if the light origin is offscreen on only one axis the result will
3629 // be exactly 5 planes (split-side case)
3630 // if the light origin is offscreen on two axes the result will be
3631 // exactly 4 planes (stretched corner case)
3632 for (i = 0;i < 4;i++)
3634 // quickly reject standard frustum planes that put the light
3635 // origin outside the frustum
3636 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3639 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3641 // if all the standard frustum planes were accepted, the light is onscreen
3642 // otherwise we need to generate some more planes below...
3643 if (rsurface.rtlight_numfrustumplanes < 4)
3645 // at least one of the stock frustum planes failed, so we need to
3646 // create one or two custom planes to enclose the light origin
3647 for (i = 0;i < 4;i++)
3649 // create a plane using the view origin and light origin, and a
3650 // single point from the frustum corner set
3651 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3652 VectorNormalize(plane.normal);
3653 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3654 // see if this plane is backwards and flip it if so
3655 for (j = 0;j < 4;j++)
3656 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3660 VectorNegate(plane.normal, plane.normal);
3662 // flipped plane, test again to see if it is now valid
3663 for (j = 0;j < 4;j++)
3664 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3666 // if the plane is still not valid, then it is dividing the
3667 // frustum and has to be rejected
3671 // we have created a valid plane, compute extra info
3672 PlaneClassify(&plane);
3674 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3676 // if we've found 5 frustum planes then we have constructed a
3677 // proper split-side case and do not need to keep searching for
3678 // planes to enclose the light origin
3679 if (rsurface.rtlight_numfrustumplanes == 5)
3687 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3689 plane = rsurface.rtlight_frustumplanes[i];
3690 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));
3695 // now add the light-space box planes if the light box is rotated, as any
3696 // caster outside the oriented light box is irrelevant (even if it passed
3697 // the worldspace light box, which is axial)
3698 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3700 for (i = 0;i < 6;i++)
3704 v[i >> 1] = (i & 1) ? -1 : 1;
3705 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3706 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3707 plane.dist = VectorNormalizeLength(plane.normal);
3708 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3709 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3715 // add the world-space reduced box planes
3716 for (i = 0;i < 6;i++)
3718 VectorClear(plane.normal);
3719 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3720 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3721 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3730 // reduce all plane distances to tightly fit the rtlight cull box, which
3732 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3733 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3734 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3735 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3736 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3737 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3738 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3739 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3740 oldnum = rsurface.rtlight_numfrustumplanes;
3741 rsurface.rtlight_numfrustumplanes = 0;
3742 for (j = 0;j < oldnum;j++)
3744 // find the nearest point on the box to this plane
3745 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3746 for (i = 1;i < 8;i++)
3748 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3749 if (bestdist > dist)
3752 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);
3753 // if the nearest point is near or behind the plane, we want this
3754 // plane, otherwise the plane is useless as it won't cull anything
3755 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3757 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3758 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3765 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3769 RSurf_ActiveWorldEntity();
3771 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3774 GL_CullFace(GL_NONE);
3775 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3776 for (;mesh;mesh = mesh->next)
3778 if (!mesh->sidetotals[r_shadow_shadowmapside])
3780 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3781 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3782 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3786 else if (r_refdef.scene.worldentity->model)
3787 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);
3789 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3792 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3797 int surfacelistindex;
3798 msurface_t *surface;
3800 RSurf_ActiveWorldEntity();
3802 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3805 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3806 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3807 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3808 for (;mesh;mesh = mesh->next)
3810 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3811 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3812 GL_LockArrays(0, mesh->numverts);
3813 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3815 // increment stencil if frontface is infront of depthbuffer
3816 GL_CullFace(r_refdef.view.cullface_back);
3817 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3818 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3819 // decrement stencil if backface is infront of depthbuffer
3820 GL_CullFace(r_refdef.view.cullface_front);
3821 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3823 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3825 // decrement stencil if backface is behind depthbuffer
3826 GL_CullFace(r_refdef.view.cullface_front);
3827 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3828 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3829 // increment stencil if frontface is behind depthbuffer
3830 GL_CullFace(r_refdef.view.cullface_back);
3831 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3833 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3834 GL_LockArrays(0, 0);
3838 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3840 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3841 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3843 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3844 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3845 if (CHECKPVSBIT(trispvs, t))
3846 shadowmarklist[numshadowmark++] = t;
3848 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);
3850 else if (numsurfaces)
3851 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3853 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3856 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3858 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3859 vec_t relativeshadowradius;
3860 RSurf_ActiveModelEntity(ent, false, false);
3861 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3862 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3863 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3864 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3865 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3866 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3867 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3868 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3869 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3871 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3874 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3875 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3878 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3880 // set up properties for rendering light onto this entity
3881 RSurf_ActiveModelEntity(ent, true, true);
3882 GL_AlphaTest(false);
3883 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3884 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3885 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3886 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3887 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3888 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3891 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3893 if (!r_refdef.scene.worldmodel->DrawLight)
3896 // set up properties for rendering light onto this entity
3897 RSurf_ActiveWorldEntity();
3898 GL_AlphaTest(false);
3899 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3900 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3901 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3902 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3903 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3904 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3906 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3908 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3911 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3913 dp_model_t *model = ent->model;
3914 if (!model->DrawLight)
3917 R_Shadow_SetupEntityLight(ent);
3919 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3921 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3924 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3928 int numleafs, numsurfaces;
3929 int *leaflist, *surfacelist;
3930 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3931 int numlightentities;
3932 int numlightentities_noselfshadow;
3933 int numshadowentities;
3934 int numshadowentities_noselfshadow;
3935 static entity_render_t *lightentities[MAX_EDICTS];
3936 static entity_render_t *shadowentities[MAX_EDICTS];
3937 static unsigned char entitysides[MAX_EDICTS];
3938 int lightentities_noselfshadow;
3939 int shadowentities_noselfshadow;
3940 vec3_t nearestpoint;
3942 qboolean castshadows;
3945 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3946 // skip lights that are basically invisible (color 0 0 0)
3947 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3950 // loading is done before visibility checks because loading should happen
3951 // all at once at the start of a level, not when it stalls gameplay.
3952 // (especially important to benchmarks)
3954 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3956 if (rtlight->compiled)
3957 R_RTLight_Uncompile(rtlight);
3958 R_RTLight_Compile(rtlight);
3962 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3964 // look up the light style value at this time
3965 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3966 VectorScale(rtlight->color, f, rtlight->currentcolor);
3968 if (rtlight->selected)
3970 f = 2 + sin(realtime * M_PI * 4.0);
3971 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3975 // if lightstyle is currently off, don't draw the light
3976 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3979 // if the light box is offscreen, skip it
3980 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3983 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3984 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3986 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3988 // compiled light, world available and can receive realtime lighting
3989 // retrieve leaf information
3990 numleafs = rtlight->static_numleafs;
3991 leaflist = rtlight->static_leaflist;
3992 leafpvs = rtlight->static_leafpvs;
3993 numsurfaces = rtlight->static_numsurfaces;
3994 surfacelist = rtlight->static_surfacelist;
3995 surfacesides = NULL;
3996 shadowtrispvs = rtlight->static_shadowtrispvs;
3997 lighttrispvs = rtlight->static_lighttrispvs;
3999 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4001 // dynamic light, world available and can receive realtime lighting
4002 // calculate lit surfaces and leafs
4003 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);
4004 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);
4005 leaflist = r_shadow_buffer_leaflist;
4006 leafpvs = r_shadow_buffer_leafpvs;
4007 surfacelist = r_shadow_buffer_surfacelist;
4008 surfacesides = r_shadow_buffer_surfacesides;
4009 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4010 lighttrispvs = r_shadow_buffer_lighttrispvs;
4011 // if the reduced leaf bounds are offscreen, skip it
4012 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4023 surfacesides = NULL;
4024 shadowtrispvs = NULL;
4025 lighttrispvs = NULL;
4027 // check if light is illuminating any visible leafs
4030 for (i = 0;i < numleafs;i++)
4031 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4036 // set up a scissor rectangle for this light
4037 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4040 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4042 // make a list of lit entities and shadow casting entities
4043 numlightentities = 0;
4044 numlightentities_noselfshadow = 0;
4045 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4046 numshadowentities = 0;
4047 numshadowentities_noselfshadow = 0;
4048 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4050 // add dynamic entities that are lit by the light
4051 if (r_drawentities.integer)
4053 for (i = 0;i < r_refdef.scene.numentities;i++)
4056 entity_render_t *ent = r_refdef.scene.entities[i];
4058 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4060 // skip the object entirely if it is not within the valid
4061 // shadow-casting region (which includes the lit region)
4062 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4064 if (!(model = ent->model))
4066 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4068 // this entity wants to receive light, is visible, and is
4069 // inside the light box
4070 // TODO: check if the surfaces in the model can receive light
4071 // so now check if it's in a leaf seen by the light
4072 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))
4074 if (ent->flags & RENDER_NOSELFSHADOW)
4075 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4077 lightentities[numlightentities++] = ent;
4078 // since it is lit, it probably also casts a shadow...
4079 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4080 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4081 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4083 // note: exterior models without the RENDER_NOSELFSHADOW
4084 // flag still create a RENDER_NOSELFSHADOW shadow but
4085 // are lit normally, this means that they are
4086 // self-shadowing but do not shadow other
4087 // RENDER_NOSELFSHADOW entities such as the gun
4088 // (very weird, but keeps the player shadow off the gun)
4089 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4090 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4092 shadowentities[numshadowentities++] = ent;
4095 else if (ent->flags & RENDER_SHADOW)
4097 // this entity is not receiving light, but may still need to
4099 // TODO: check if the surfaces in the model can cast shadow
4100 // now check if it is in a leaf seen by the light
4101 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))
4103 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4104 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4105 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4107 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4108 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4110 shadowentities[numshadowentities++] = ent;
4116 // return if there's nothing at all to light
4117 if (!numlightentities && !numsurfaces)
4120 // don't let sound skip if going slow
4121 if (r_refdef.scene.extraupdate)
4124 // make this the active rtlight for rendering purposes
4125 R_Shadow_RenderMode_ActiveLight(rtlight);
4126 // count this light in the r_speeds
4127 r_refdef.stats.lights++;
4129 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4131 // optionally draw visible shape of the shadow volumes
4132 // for performance analysis by level designers
4133 R_Shadow_RenderMode_VisibleShadowVolumes();
4135 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4136 for (i = 0;i < numshadowentities;i++)
4137 R_Shadow_DrawEntityShadow(shadowentities[i]);
4138 for (i = 0;i < numshadowentities_noselfshadow;i++)
4139 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4142 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4144 // optionally draw the illuminated areas
4145 // for performance analysis by level designers
4146 R_Shadow_RenderMode_VisibleLighting(false, false);
4148 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4149 for (i = 0;i < numlightentities;i++)
4150 R_Shadow_DrawEntityLight(lightentities[i]);
4151 for (i = 0;i < numlightentities_noselfshadow;i++)
4152 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4155 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4157 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4158 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4159 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4160 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4162 // VorteX: loosy quality mode, might be good in some situations
4163 if (r_shadow_shadowmapping_quality.value)
4164 lodlinear = ( rtlight->radius * r_shadow_shadowmapping_quality.value ) / pow ( max(1.0f,(distance/rtlight->radius)), 0.5 );
4166 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4167 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4169 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4175 int receivermask = 0;
4176 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4177 Matrix4x4_Abs(&radiustolight);
4179 r_shadow_shadowmaplod = 0;
4180 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4181 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4182 r_shadow_shadowmaplod = i;
4184 size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4185 size = bound(1, size, 2048);
4186 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4190 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4192 castermask = rtlight->static_shadowmap_casters;
4193 receivermask = rtlight->static_shadowmap_receivers;
4197 for(i = 0;i < numsurfaces;i++)
4199 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4200 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4201 castermask |= surfacesides[i];
4202 receivermask |= surfacesides[i];
4206 if (receivermask < 0x3F)
4208 for (i = 0;i < numlightentities;i++)
4209 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4210 if (receivermask < 0x3F)
4211 for(i = 0; i < numlightentities_noselfshadow;i++)
4212 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4215 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4219 for (i = 0;i < numshadowentities;i++)
4220 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4221 for (i = 0;i < numshadowentities_noselfshadow;i++)
4222 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4225 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4227 // render shadow casters into 6 sided depth texture
4228 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4230 R_Shadow_RenderMode_ShadowMap(side, true, size);
4231 if (! (castermask & (1 << side))) continue;
4233 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4234 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4235 R_Shadow_DrawEntityShadow(shadowentities[i]);
4238 if (numlightentities_noselfshadow)
4240 // render lighting using the depth texture as shadowmap
4241 // draw lighting in the unmasked areas
4242 R_Shadow_RenderMode_Lighting(false, false, true);
4243 for (i = 0;i < numlightentities_noselfshadow;i++)
4244 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4247 // render shadow casters into 6 sided depth texture
4248 if (numshadowentities_noselfshadow)
4250 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4252 R_Shadow_RenderMode_ShadowMap(side, false, size);
4253 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4254 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4258 // render lighting using the depth texture as shadowmap
4259 // draw lighting in the unmasked areas
4260 R_Shadow_RenderMode_Lighting(false, false, true);
4261 // draw lighting in the unmasked areas
4263 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4264 for (i = 0;i < numlightentities;i++)
4265 R_Shadow_DrawEntityLight(lightentities[i]);
4267 else if (castshadows && gl_stencil)
4269 // draw stencil shadow volumes to mask off pixels that are in shadow
4270 // so that they won't receive lighting
4271 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4272 R_Shadow_ClearStencil();
4274 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4275 for (i = 0;i < numshadowentities;i++)
4276 R_Shadow_DrawEntityShadow(shadowentities[i]);
4277 if (numlightentities_noselfshadow)
4279 // draw lighting in the unmasked areas
4280 R_Shadow_RenderMode_Lighting(true, false, false);
4281 for (i = 0;i < numlightentities_noselfshadow;i++)
4282 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4284 // optionally draw the illuminated areas
4285 // for performance analysis by level designers
4286 if (r_showlighting.integer && r_refdef.view.showdebug)
4288 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4289 for (i = 0;i < numlightentities_noselfshadow;i++)
4290 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4293 for (i = 0;i < numshadowentities_noselfshadow;i++)
4294 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4296 if (numsurfaces + numlightentities)
4298 // draw lighting in the unmasked areas
4299 R_Shadow_RenderMode_Lighting(true, false, false);
4301 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4302 for (i = 0;i < numlightentities;i++)
4303 R_Shadow_DrawEntityLight(lightentities[i]);
4308 if (numsurfaces + numlightentities)
4310 // draw lighting in the unmasked areas
4311 R_Shadow_RenderMode_Lighting(false, false, false);
4313 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4314 for (i = 0;i < numlightentities;i++)
4315 R_Shadow_DrawEntityLight(lightentities[i]);
4316 for (i = 0;i < numlightentities_noselfshadow;i++)
4317 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4322 void R_Shadow_DrawLightSprites(void);
4323 void R_ShadowVolumeLighting(qboolean visible)
4331 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4332 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) ||
4333 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4334 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4335 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4336 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4337 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4338 R_Shadow_FreeShadowMaps();
4340 if (r_editlights.integer)
4341 R_Shadow_DrawLightSprites();
4343 R_Shadow_RenderMode_Begin();
4345 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4346 if (r_shadow_debuglight.integer >= 0)
4348 lightindex = r_shadow_debuglight.integer;
4349 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4350 if (light && (light->flags & flag))
4351 R_DrawRTLight(&light->rtlight, visible);
4355 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4356 for (lightindex = 0;lightindex < range;lightindex++)
4358 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4359 if (light && (light->flags & flag))
4360 R_DrawRTLight(&light->rtlight, visible);
4363 if (r_refdef.scene.rtdlight)
4364 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4365 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4367 R_Shadow_RenderMode_End();
4370 extern const float r_screenvertex3f[12];
4371 extern void R_SetupView(qboolean allowwaterclippingplane);
4372 extern void R_ResetViewRendering3D(void);
4373 extern void R_ResetViewRendering2D(void);
4374 extern cvar_t r_shadows;
4375 extern cvar_t r_shadows_darken;
4376 extern cvar_t r_shadows_drawafterrtlighting;
4377 extern cvar_t r_shadows_castfrombmodels;
4378 extern cvar_t r_shadows_throwdistance;
4379 extern cvar_t r_shadows_throwdirection;
4380 void R_DrawModelShadows(void)
4383 float relativethrowdistance;
4384 entity_render_t *ent;
4385 vec3_t relativelightorigin;
4386 vec3_t relativelightdirection;
4387 vec3_t relativeshadowmins, relativeshadowmaxs;
4388 vec3_t tmp, shadowdir;
4390 if (!r_drawentities.integer || !gl_stencil)
4394 R_ResetViewRendering3D();
4395 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4396 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4397 R_Shadow_RenderMode_Begin();
4398 R_Shadow_RenderMode_ActiveLight(NULL);
4399 r_shadow_lightscissor[0] = r_refdef.view.x;
4400 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4401 r_shadow_lightscissor[2] = r_refdef.view.width;
4402 r_shadow_lightscissor[3] = r_refdef.view.height;
4403 R_Shadow_RenderMode_StencilShadowVolumes(false);
4406 if (r_shadows.integer == 2)
4408 Math_atov(r_shadows_throwdirection.string, shadowdir);
4409 VectorNormalize(shadowdir);
4412 R_Shadow_ClearStencil();
4414 for (i = 0;i < r_refdef.scene.numentities;i++)
4416 ent = r_refdef.scene.entities[i];
4418 // cast shadows from anything of the map (submodels are optional)
4419 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4421 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4422 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4423 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4424 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4425 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4428 if(ent->entitynumber != 0)
4430 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4431 int entnum, entnum2, recursion;
4432 entnum = entnum2 = ent->entitynumber;
4433 for(recursion = 32; recursion > 0; --recursion)
4435 entnum2 = cl.entities[entnum].state_current.tagentity;
4436 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4441 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4443 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4444 // transform into modelspace of OUR entity
4445 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4446 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4449 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4452 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4455 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4456 RSurf_ActiveModelEntity(ent, false, false);
4457 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4458 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4462 // not really the right mode, but this will disable any silly stencil features
4463 R_Shadow_RenderMode_End();
4465 // set up ortho view for rendering this pass
4466 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4467 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4468 //GL_ScissorTest(true);
4469 //R_Mesh_Matrix(&identitymatrix);
4470 //R_Mesh_ResetTextureState();
4471 R_ResetViewRendering2D();
4472 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4473 R_Mesh_ColorPointer(NULL, 0, 0);
4474 R_SetupGenericShader(false);
4476 // set up a darkening blend on shadowed areas
4477 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4478 //GL_DepthRange(0, 1);
4479 //GL_DepthTest(false);
4480 //GL_DepthMask(false);
4481 //GL_PolygonOffset(0, 0);CHECKGLERROR
4482 GL_Color(0, 0, 0, r_shadows_darken.value);
4483 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4484 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4485 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4486 qglStencilMask(~0);CHECKGLERROR
4487 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4488 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4490 // apply the blend to the shadowed areas
4491 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4493 // restore the viewport
4494 R_SetViewport(&r_refdef.view.viewport);
4496 // restore other state to normal
4497 //R_Shadow_RenderMode_End();
4500 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4503 vec3_t centerorigin;
4504 // if it's too close, skip it
4505 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4507 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4510 if (usequery && r_numqueries + 2 <= r_maxqueries)
4512 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4513 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4514 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4517 // 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
4518 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4519 qglDepthFunc(GL_ALWAYS);
4520 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);
4521 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4522 qglDepthFunc(GL_LEQUAL);
4523 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4524 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);
4525 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4528 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4531 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4534 GLint allpixels = 0, visiblepixels = 0;
4535 // now we have to check the query result
4536 if (rtlight->corona_queryindex_visiblepixels)
4539 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4540 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4542 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4543 if (visiblepixels < 1 || allpixels < 1)
4545 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4546 cscale *= rtlight->corona_visibility;
4550 // FIXME: these traces should scan all render entities instead of cl.world
4551 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4554 VectorScale(rtlight->color, cscale, color);
4555 if (VectorLength(color) > (1.0f / 256.0f))
4556 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);
4559 void R_DrawCoronas(void)
4567 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4569 if (r_waterstate.renderingscene)
4571 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4572 R_Mesh_Matrix(&identitymatrix);
4574 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4576 // check occlusion of coronas
4577 // use GL_ARB_occlusion_query if available
4578 // otherwise use raytraces
4580 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4583 GL_ColorMask(0,0,0,0);
4584 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4585 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4588 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4589 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4591 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4595 for (lightindex = 0;lightindex < range;lightindex++)
4597 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4600 rtlight = &light->rtlight;
4601 rtlight->corona_visibility = 0;
4602 rtlight->corona_queryindex_visiblepixels = 0;
4603 rtlight->corona_queryindex_allpixels = 0;
4604 if (!(rtlight->flags & flag))
4606 if (rtlight->corona <= 0)
4608 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4610 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4612 for (i = 0;i < r_refdef.scene.numlights;i++)
4614 rtlight = r_refdef.scene.lights[i];
4615 rtlight->corona_visibility = 0;
4616 rtlight->corona_queryindex_visiblepixels = 0;
4617 rtlight->corona_queryindex_allpixels = 0;
4618 if (!(rtlight->flags & flag))
4620 if (rtlight->corona <= 0)
4622 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4625 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4627 // now draw the coronas using the query data for intensity info
4628 for (lightindex = 0;lightindex < range;lightindex++)
4630 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4633 rtlight = &light->rtlight;
4634 if (rtlight->corona_visibility <= 0)
4636 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4638 for (i = 0;i < r_refdef.scene.numlights;i++)
4640 rtlight = r_refdef.scene.lights[i];
4641 if (rtlight->corona_visibility <= 0)
4643 if (gl_flashblend.integer)
4644 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4646 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4652 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4653 typedef struct suffixinfo_s
4656 qboolean flipx, flipy, flipdiagonal;
4659 static suffixinfo_t suffix[3][6] =
4662 {"px", false, false, false},
4663 {"nx", false, false, false},
4664 {"py", false, false, false},
4665 {"ny", false, false, false},
4666 {"pz", false, false, false},
4667 {"nz", false, false, false}
4670 {"posx", false, false, false},
4671 {"negx", false, false, false},
4672 {"posy", false, false, false},
4673 {"negy", false, false, false},
4674 {"posz", false, false, false},
4675 {"negz", false, false, false}
4678 {"rt", true, false, true},
4679 {"lf", false, true, true},
4680 {"ft", true, true, false},
4681 {"bk", false, false, false},
4682 {"up", true, false, true},
4683 {"dn", true, false, true}
4687 static int componentorder[4] = {0, 1, 2, 3};
4689 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4691 int i, j, cubemapsize;
4692 unsigned char *cubemappixels, *image_buffer;
4693 rtexture_t *cubemaptexture;
4695 // must start 0 so the first loadimagepixels has no requested width/height
4697 cubemappixels = NULL;
4698 cubemaptexture = NULL;
4699 // keep trying different suffix groups (posx, px, rt) until one loads
4700 for (j = 0;j < 3 && !cubemappixels;j++)
4702 // load the 6 images in the suffix group
4703 for (i = 0;i < 6;i++)
4705 // generate an image name based on the base and and suffix
4706 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4708 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4710 // an image loaded, make sure width and height are equal
4711 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4713 // if this is the first image to load successfully, allocate the cubemap memory
4714 if (!cubemappixels && image_width >= 1)
4716 cubemapsize = image_width;
4717 // note this clears to black, so unavailable sides are black
4718 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4720 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4722 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);
4725 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4727 Mem_Free(image_buffer);
4731 // if a cubemap loaded, upload it
4734 if (developer_loading.integer)
4735 Con_Printf("loading cubemap \"%s\"\n", basename);
4737 if (!r_shadow_filters_texturepool)
4738 r_shadow_filters_texturepool = R_AllocTexturePool();
4739 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4740 Mem_Free(cubemappixels);
4744 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4745 if (developer_loading.integer)
4747 Con_Printf("(tried tried images ");
4748 for (j = 0;j < 3;j++)
4749 for (i = 0;i < 6;i++)
4750 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4751 Con_Print(" and was unable to find any of them).\n");
4754 return cubemaptexture;
4757 rtexture_t *R_Shadow_Cubemap(const char *basename)
4760 for (i = 0;i < numcubemaps;i++)
4761 if (!strcasecmp(cubemaps[i].basename, basename))
4762 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4763 if (i >= MAX_CUBEMAPS)
4764 return r_texture_whitecube;
4766 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4767 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4768 return cubemaps[i].texture;
4771 void R_Shadow_FreeCubemaps(void)
4774 for (i = 0;i < numcubemaps;i++)
4776 if (developer_loading.integer)
4777 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4778 if (cubemaps[i].texture)
4779 R_FreeTexture(cubemaps[i].texture);
4783 R_FreeTexturePool(&r_shadow_filters_texturepool);
4786 dlight_t *R_Shadow_NewWorldLight(void)
4788 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4791 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)
4794 // validate parameters
4795 if (style < 0 || style >= MAX_LIGHTSTYLES)
4797 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4803 // copy to light properties
4804 VectorCopy(origin, light->origin);
4805 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4806 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4807 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4808 light->color[0] = max(color[0], 0);
4809 light->color[1] = max(color[1], 0);
4810 light->color[2] = max(color[2], 0);
4811 light->radius = max(radius, 0);
4812 light->style = style;
4813 light->shadow = shadowenable;
4814 light->corona = corona;
4815 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4816 light->coronasizescale = coronasizescale;
4817 light->ambientscale = ambientscale;
4818 light->diffusescale = diffusescale;
4819 light->specularscale = specularscale;
4820 light->flags = flags;
4822 // update renderable light data
4823 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4824 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);
4827 void R_Shadow_FreeWorldLight(dlight_t *light)
4829 if (r_shadow_selectedlight == light)
4830 r_shadow_selectedlight = NULL;
4831 R_RTLight_Uncompile(&light->rtlight);
4832 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4835 void R_Shadow_ClearWorldLights(void)
4839 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4840 for (lightindex = 0;lightindex < range;lightindex++)
4842 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4844 R_Shadow_FreeWorldLight(light);
4846 r_shadow_selectedlight = NULL;
4847 R_Shadow_FreeCubemaps();
4850 void R_Shadow_SelectLight(dlight_t *light)
4852 if (r_shadow_selectedlight)
4853 r_shadow_selectedlight->selected = false;
4854 r_shadow_selectedlight = light;
4855 if (r_shadow_selectedlight)
4856 r_shadow_selectedlight->selected = true;
4859 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4861 // this is never batched (there can be only one)
4862 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);
4865 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4872 // this is never batched (due to the ent parameter changing every time)
4873 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4874 const dlight_t *light = (dlight_t *)ent;
4877 VectorScale(light->color, intensity, spritecolor);
4878 if (VectorLength(spritecolor) < 0.1732f)
4879 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4880 if (VectorLength(spritecolor) > 1.0f)
4881 VectorNormalize(spritecolor);
4883 // draw light sprite
4884 if (light->cubemapname[0] && !light->shadow)
4885 pic = r_editlights_sprcubemapnoshadowlight;
4886 else if (light->cubemapname[0])
4887 pic = r_editlights_sprcubemaplight;
4888 else if (!light->shadow)
4889 pic = r_editlights_sprnoshadowlight;
4891 pic = r_editlights_sprlight;
4892 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);
4893 // draw selection sprite if light is selected
4894 if (light->selected)
4895 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);
4896 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4899 void R_Shadow_DrawLightSprites(void)
4903 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4904 for (lightindex = 0;lightindex < range;lightindex++)
4906 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4908 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4910 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4913 void R_Shadow_SelectLightInView(void)
4915 float bestrating, rating, temp[3];
4919 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4922 for (lightindex = 0;lightindex < range;lightindex++)
4924 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4927 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4928 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4931 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4932 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4934 bestrating = rating;
4939 R_Shadow_SelectLight(best);
4942 void R_Shadow_LoadWorldLights(void)
4944 int n, a, style, shadow, flags;
4945 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4946 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4947 if (cl.worldmodel == NULL)
4949 Con_Print("No map loaded.\n");
4952 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4953 strlcat (name, ".rtlights", sizeof (name));
4954 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4964 for (;COM_Parse(t, true) && strcmp(
4965 if (COM_Parse(t, true))
4967 if (com_token[0] == '!')
4970 origin[0] = atof(com_token+1);
4973 origin[0] = atof(com_token);
4978 while (*s && *s != '\n' && *s != '\r')
4984 // check for modifier flags
4991 #if _MSC_VER >= 1400
4992 #define sscanf sscanf_s
4994 cubemapname[sizeof(cubemapname)-1] = 0;
4995 #if MAX_QPATH != 128
4996 #error update this code if MAX_QPATH changes
4998 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
4999 #if _MSC_VER >= 1400
5000 , sizeof(cubemapname)
5002 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5005 flags = LIGHTFLAG_REALTIMEMODE;
5013 coronasizescale = 0.25f;
5015 VectorClear(angles);
5018 if (a < 9 || !strcmp(cubemapname, "\"\""))
5020 // remove quotes on cubemapname
5021 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5024 namelen = strlen(cubemapname) - 2;
5025 memmove(cubemapname, cubemapname + 1, namelen);
5026 cubemapname[namelen] = '\0';
5030 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);
5033 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5041 Con_Printf("invalid rtlights file \"%s\"\n", name);
5042 Mem_Free(lightsstring);
5046 void R_Shadow_SaveWorldLights(void)
5050 size_t bufchars, bufmaxchars;
5052 char name[MAX_QPATH];
5053 char line[MAX_INPUTLINE];
5054 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5055 // I hate lines which are 3 times my screen size :( --blub
5058 if (cl.worldmodel == NULL)
5060 Con_Print("No map loaded.\n");
5063 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5064 strlcat (name, ".rtlights", sizeof (name));
5065 bufchars = bufmaxchars = 0;
5067 for (lightindex = 0;lightindex < range;lightindex++)
5069 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5072 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5073 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);
5074 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5075 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]);
5077 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);
5078 if (bufchars + strlen(line) > bufmaxchars)
5080 bufmaxchars = bufchars + strlen(line) + 2048;
5082 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5086 memcpy(buf, oldbuf, bufchars);
5092 memcpy(buf + bufchars, line, strlen(line));
5093 bufchars += strlen(line);
5097 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5102 void R_Shadow_LoadLightsFile(void)
5105 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5106 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5107 if (cl.worldmodel == NULL)
5109 Con_Print("No map loaded.\n");
5112 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5113 strlcat (name, ".lights", sizeof (name));
5114 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5122 while (*s && *s != '\n' && *s != '\r')
5128 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);
5132 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);
5135 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5136 radius = bound(15, radius, 4096);
5137 VectorScale(color, (2.0f / (8388608.0f)), color);
5138 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5146 Con_Printf("invalid lights file \"%s\"\n", name);
5147 Mem_Free(lightsstring);
5151 // tyrlite/hmap2 light types in the delay field
5152 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5154 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5156 int entnum, style, islight, skin, pflags, effects, type, n;
5159 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5160 char key[256], value[MAX_INPUTLINE];
5162 if (cl.worldmodel == NULL)
5164 Con_Print("No map loaded.\n");
5167 // try to load a .ent file first
5168 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5169 strlcat (key, ".ent", sizeof (key));
5170 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5171 // and if that is not found, fall back to the bsp file entity string
5173 data = cl.worldmodel->brush.entities;
5176 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5178 type = LIGHTTYPE_MINUSX;
5179 origin[0] = origin[1] = origin[2] = 0;
5180 originhack[0] = originhack[1] = originhack[2] = 0;
5181 angles[0] = angles[1] = angles[2] = 0;
5182 color[0] = color[1] = color[2] = 1;
5183 light[0] = light[1] = light[2] = 1;light[3] = 300;
5184 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5194 if (!COM_ParseToken_Simple(&data, false, false))
5196 if (com_token[0] == '}')
5197 break; // end of entity
5198 if (com_token[0] == '_')
5199 strlcpy(key, com_token + 1, sizeof(key));
5201 strlcpy(key, com_token, sizeof(key));
5202 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5203 key[strlen(key)-1] = 0;
5204 if (!COM_ParseToken_Simple(&data, false, false))
5206 strlcpy(value, com_token, sizeof(value));
5208 // now that we have the key pair worked out...
5209 if (!strcmp("light", key))
5211 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5215 light[0] = vec[0] * (1.0f / 256.0f);
5216 light[1] = vec[0] * (1.0f / 256.0f);
5217 light[2] = vec[0] * (1.0f / 256.0f);
5223 light[0] = vec[0] * (1.0f / 255.0f);
5224 light[1] = vec[1] * (1.0f / 255.0f);
5225 light[2] = vec[2] * (1.0f / 255.0f);
5229 else if (!strcmp("delay", key))
5231 else if (!strcmp("origin", key))
5232 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5233 else if (!strcmp("angle", key))
5234 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5235 else if (!strcmp("angles", key))
5236 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5237 else if (!strcmp("color", key))
5238 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5239 else if (!strcmp("wait", key))
5240 fadescale = atof(value);
5241 else if (!strcmp("classname", key))
5243 if (!strncmp(value, "light", 5))
5246 if (!strcmp(value, "light_fluoro"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 1;
5253 overridecolor[2] = 1;
5255 if (!strcmp(value, "light_fluorospark"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 1;
5262 overridecolor[2] = 1;
5264 if (!strcmp(value, "light_globe"))
5269 overridecolor[0] = 1;
5270 overridecolor[1] = 0.8;
5271 overridecolor[2] = 0.4;
5273 if (!strcmp(value, "light_flame_large_yellow"))
5278 overridecolor[0] = 1;
5279 overridecolor[1] = 0.5;
5280 overridecolor[2] = 0.1;
5282 if (!strcmp(value, "light_flame_small_yellow"))
5287 overridecolor[0] = 1;
5288 overridecolor[1] = 0.5;
5289 overridecolor[2] = 0.1;
5291 if (!strcmp(value, "light_torch_small_white"))
5296 overridecolor[0] = 1;
5297 overridecolor[1] = 0.5;
5298 overridecolor[2] = 0.1;
5300 if (!strcmp(value, "light_torch_small_walltorch"))
5305 overridecolor[0] = 1;
5306 overridecolor[1] = 0.5;
5307 overridecolor[2] = 0.1;
5311 else if (!strcmp("style", key))
5312 style = atoi(value);
5313 else if (!strcmp("skin", key))
5314 skin = (int)atof(value);
5315 else if (!strcmp("pflags", key))
5316 pflags = (int)atof(value);
5317 else if (!strcmp("effects", key))
5318 effects = (int)atof(value);
5319 else if (cl.worldmodel->type == mod_brushq3)
5321 if (!strcmp("scale", key))
5322 lightscale = atof(value);
5323 if (!strcmp("fade", key))
5324 fadescale = atof(value);
5329 if (lightscale <= 0)
5333 if (color[0] == color[1] && color[0] == color[2])
5335 color[0] *= overridecolor[0];
5336 color[1] *= overridecolor[1];
5337 color[2] *= overridecolor[2];
5339 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5340 color[0] = color[0] * light[0];
5341 color[1] = color[1] * light[1];
5342 color[2] = color[2] * light[2];
5345 case LIGHTTYPE_MINUSX:
5347 case LIGHTTYPE_RECIPX:
5349 VectorScale(color, (1.0f / 16.0f), color);
5351 case LIGHTTYPE_RECIPXX:
5353 VectorScale(color, (1.0f / 16.0f), color);
5356 case LIGHTTYPE_NONE:
5360 case LIGHTTYPE_MINUSXX:
5363 VectorAdd(origin, originhack, origin);
5365 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);
5368 Mem_Free(entfiledata);
5372 void R_Shadow_SetCursorLocationForView(void)
5375 vec3_t dest, endpos;
5377 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5378 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5379 if (trace.fraction < 1)
5381 dist = trace.fraction * r_editlights_cursordistance.value;
5382 push = r_editlights_cursorpushback.value;
5386 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5387 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5391 VectorClear( endpos );
5393 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5394 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5395 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5398 void R_Shadow_UpdateWorldLightSelection(void)
5400 if (r_editlights.integer)
5402 R_Shadow_SetCursorLocationForView();
5403 R_Shadow_SelectLightInView();
5406 R_Shadow_SelectLight(NULL);
5409 void R_Shadow_EditLights_Clear_f(void)
5411 R_Shadow_ClearWorldLights();
5414 void R_Shadow_EditLights_Reload_f(void)
5418 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5419 R_Shadow_ClearWorldLights();
5420 R_Shadow_LoadWorldLights();
5421 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5423 R_Shadow_LoadLightsFile();
5424 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5425 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5429 void R_Shadow_EditLights_Save_f(void)
5433 R_Shadow_SaveWorldLights();
5436 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5438 R_Shadow_ClearWorldLights();
5439 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5442 void R_Shadow_EditLights_ImportLightsFile_f(void)
5444 R_Shadow_ClearWorldLights();
5445 R_Shadow_LoadLightsFile();
5448 void R_Shadow_EditLights_Spawn_f(void)
5451 if (!r_editlights.integer)
5453 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5456 if (Cmd_Argc() != 1)
5458 Con_Print("r_editlights_spawn does not take parameters\n");
5461 color[0] = color[1] = color[2] = 1;
5462 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5465 void R_Shadow_EditLights_Edit_f(void)
5467 vec3_t origin, angles, color;
5468 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5469 int style, shadows, flags, normalmode, realtimemode;
5470 char cubemapname[MAX_INPUTLINE];
5471 if (!r_editlights.integer)
5473 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5476 if (!r_shadow_selectedlight)
5478 Con_Print("No selected light.\n");
5481 VectorCopy(r_shadow_selectedlight->origin, origin);
5482 VectorCopy(r_shadow_selectedlight->angles, angles);
5483 VectorCopy(r_shadow_selectedlight->color, color);
5484 radius = r_shadow_selectedlight->radius;
5485 style = r_shadow_selectedlight->style;
5486 if (r_shadow_selectedlight->cubemapname)
5487 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5490 shadows = r_shadow_selectedlight->shadow;
5491 corona = r_shadow_selectedlight->corona;
5492 coronasizescale = r_shadow_selectedlight->coronasizescale;
5493 ambientscale = r_shadow_selectedlight->ambientscale;
5494 diffusescale = r_shadow_selectedlight->diffusescale;
5495 specularscale = r_shadow_selectedlight->specularscale;
5496 flags = r_shadow_selectedlight->flags;
5497 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5498 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5499 if (!strcmp(Cmd_Argv(1), "origin"))
5501 if (Cmd_Argc() != 5)
5503 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5506 origin[0] = atof(Cmd_Argv(2));
5507 origin[1] = atof(Cmd_Argv(3));
5508 origin[2] = atof(Cmd_Argv(4));
5510 else if (!strcmp(Cmd_Argv(1), "originx"))
5512 if (Cmd_Argc() != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5517 origin[0] = atof(Cmd_Argv(2));
5519 else if (!strcmp(Cmd_Argv(1), "originy"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 origin[1] = atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "originz"))
5530 if (Cmd_Argc() != 3)
5532 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5535 origin[2] = atof(Cmd_Argv(2));
5537 else if (!strcmp(Cmd_Argv(1), "move"))
5539 if (Cmd_Argc() != 5)
5541 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5544 origin[0] += atof(Cmd_Argv(2));
5545 origin[1] += atof(Cmd_Argv(3));
5546 origin[2] += atof(Cmd_Argv(4));
5548 else if (!strcmp(Cmd_Argv(1), "movex"))
5550 if (Cmd_Argc() != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5555 origin[0] += atof(Cmd_Argv(2));
5557 else if (!strcmp(Cmd_Argv(1), "movey"))
5559 if (Cmd_Argc() != 3)
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 origin[1] += atof(Cmd_Argv(2));
5566 else if (!strcmp(Cmd_Argv(1), "movez"))
5568 if (Cmd_Argc() != 3)
5570 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5573 origin[2] += atof(Cmd_Argv(2));
5575 else if (!strcmp(Cmd_Argv(1), "angles"))
5577 if (Cmd_Argc() != 5)
5579 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5582 angles[0] = atof(Cmd_Argv(2));
5583 angles[1] = atof(Cmd_Argv(3));
5584 angles[2] = atof(Cmd_Argv(4));
5586 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5588 if (Cmd_Argc() != 3)
5590 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5593 angles[0] = atof(Cmd_Argv(2));
5595 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5597 if (Cmd_Argc() != 3)
5599 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5602 angles[1] = atof(Cmd_Argv(2));
5604 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 angles[2] = atof(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "color"))
5615 if (Cmd_Argc() != 5)
5617 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5620 color[0] = atof(Cmd_Argv(2));
5621 color[1] = atof(Cmd_Argv(3));
5622 color[2] = atof(Cmd_Argv(4));
5624 else if (!strcmp(Cmd_Argv(1), "radius"))
5626 if (Cmd_Argc() != 3)
5628 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5631 radius = atof(Cmd_Argv(2));
5633 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5635 if (Cmd_Argc() == 3)
5637 double scale = atof(Cmd_Argv(2));
5644 if (Cmd_Argc() != 5)
5646 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5649 color[0] *= atof(Cmd_Argv(2));
5650 color[1] *= atof(Cmd_Argv(3));
5651 color[2] *= atof(Cmd_Argv(4));
5654 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 radius *= atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "style"))
5665 if (Cmd_Argc() != 3)
5667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5670 style = atoi(Cmd_Argv(2));
5672 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5679 if (Cmd_Argc() == 3)
5680 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5684 else if (!strcmp(Cmd_Argv(1), "shadows"))
5686 if (Cmd_Argc() != 3)
5688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5691 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5693 else if (!strcmp(Cmd_Argv(1), "corona"))
5695 if (Cmd_Argc() != 3)
5697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5700 corona = atof(Cmd_Argv(2));
5702 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5704 if (Cmd_Argc() != 3)
5706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5709 coronasizescale = atof(Cmd_Argv(2));
5711 else if (!strcmp(Cmd_Argv(1), "ambient"))
5713 if (Cmd_Argc() != 3)
5715 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5718 ambientscale = atof(Cmd_Argv(2));
5720 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5722 if (Cmd_Argc() != 3)
5724 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5727 diffusescale = atof(Cmd_Argv(2));
5729 else if (!strcmp(Cmd_Argv(1), "specular"))
5731 if (Cmd_Argc() != 3)
5733 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5736 specularscale = atof(Cmd_Argv(2));
5738 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5740 if (Cmd_Argc() != 3)
5742 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5745 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5747 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5749 if (Cmd_Argc() != 3)
5751 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5754 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5758 Con_Print("usage: r_editlights_edit [property] [value]\n");
5759 Con_Print("Selected light's properties:\n");
5760 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5761 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5762 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5763 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5764 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5765 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5766 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5767 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5768 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5769 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5770 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5771 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5772 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5773 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5776 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5777 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5780 void R_Shadow_EditLights_EditAll_f(void)
5786 if (!r_editlights.integer)
5788 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5792 // EditLights doesn't seem to have a "remove" command or something so:
5793 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5794 for (lightindex = 0;lightindex < range;lightindex++)
5796 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5799 R_Shadow_SelectLight(light);
5800 R_Shadow_EditLights_Edit_f();
5804 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5806 int lightnumber, lightcount;
5807 size_t lightindex, range;
5811 if (!r_editlights.integer)
5813 x = vid_conwidth.value - 240;
5815 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5818 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5819 for (lightindex = 0;lightindex < range;lightindex++)
5821 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5824 if (light == r_shadow_selectedlight)
5825 lightnumber = lightindex;
5828 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;
5829 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;
5831 if (r_shadow_selectedlight == NULL)
5833 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;
5834 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;
5835 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5845 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;
5846 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;
5847 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;
5850 void R_Shadow_EditLights_ToggleShadow_f(void)
5852 if (!r_editlights.integer)
5854 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5857 if (!r_shadow_selectedlight)
5859 Con_Print("No selected light.\n");
5862 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);
5865 void R_Shadow_EditLights_ToggleCorona_f(void)
5867 if (!r_editlights.integer)
5869 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5872 if (!r_shadow_selectedlight)
5874 Con_Print("No selected light.\n");
5877 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);
5880 void R_Shadow_EditLights_Remove_f(void)
5882 if (!r_editlights.integer)
5884 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5887 if (!r_shadow_selectedlight)
5889 Con_Print("No selected light.\n");
5892 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5893 r_shadow_selectedlight = NULL;
5896 void R_Shadow_EditLights_Help_f(void)
5899 "Documentation on r_editlights system:\n"
5901 "r_editlights : enable/disable editing mode\n"
5902 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5903 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5904 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5905 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5906 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5908 "r_editlights_help : this help\n"
5909 "r_editlights_clear : remove all lights\n"
5910 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5911 "r_editlights_save : save to .rtlights file\n"
5912 "r_editlights_spawn : create a light with default settings\n"
5913 "r_editlights_edit command : edit selected light - more documentation below\n"
5914 "r_editlights_remove : remove selected light\n"
5915 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5916 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5917 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5919 "origin x y z : set light location\n"
5920 "originx x: set x component of light location\n"
5921 "originy y: set y component of light location\n"
5922 "originz z: set z component of light location\n"
5923 "move x y z : adjust light location\n"
5924 "movex x: adjust x component of light location\n"
5925 "movey y: adjust y component of light location\n"
5926 "movez z: adjust z component of light location\n"
5927 "angles x y z : set light angles\n"
5928 "anglesx x: set x component of light angles\n"
5929 "anglesy y: set y component of light angles\n"
5930 "anglesz z: set z component of light angles\n"
5931 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5932 "radius radius : set radius (size) of light\n"
5933 "colorscale grey : multiply color of light (1 does nothing)\n"
5934 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5935 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5936 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5937 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5938 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5939 "shadows 1/0 : turn on/off shadows\n"
5940 "corona n : set corona intensity\n"
5941 "coronasize n : set corona size (0-1)\n"
5942 "ambient n : set ambient intensity (0-1)\n"
5943 "diffuse n : set diffuse intensity (0-1)\n"
5944 "specular n : set specular intensity (0-1)\n"
5945 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5946 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5947 "<nothing> : print light properties to console\n"
5951 void R_Shadow_EditLights_CopyInfo_f(void)
5953 if (!r_editlights.integer)
5955 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5958 if (!r_shadow_selectedlight)
5960 Con_Print("No selected light.\n");
5963 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5964 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5965 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5966 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5967 if (r_shadow_selectedlight->cubemapname)
5968 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5970 r_shadow_bufferlight.cubemapname[0] = 0;
5971 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5972 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5973 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5974 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5975 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5976 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5977 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5980 void R_Shadow_EditLights_PasteInfo_f(void)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5987 if (!r_shadow_selectedlight)
5989 Con_Print("No selected light.\n");
5992 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);
5995 void R_Shadow_EditLights_Init(void)
5997 Cvar_RegisterVariable(&r_editlights);
5998 Cvar_RegisterVariable(&r_editlights_cursordistance);
5999 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6000 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6001 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6002 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6003 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6004 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6005 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)");
6006 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6007 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6008 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6009 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)");
6010 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6011 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6012 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6013 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6014 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6015 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6016 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)");
6022 =============================================================================
6026 =============================================================================
6029 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6031 VectorClear(diffusecolor);
6032 VectorClear(diffusenormal);
6034 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6036 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6037 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6040 VectorSet(ambientcolor, 1, 1, 1);
6047 for (i = 0;i < r_refdef.scene.numlights;i++)
6049 light = r_refdef.scene.lights[i];
6050 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6051 f = 1 - VectorLength2(v);
6052 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6053 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);