3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 rtexture_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmaprectangletexture;
248 rtexture_t *r_shadow_shadowmap2dtexture;
249 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 // lights are reloaded when this changes
255 char r_shadow_mapname[MAX_QPATH];
257 // used only for light filters (cubemaps)
258 rtexturepool_t *r_shadow_filters_texturepool;
260 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
261 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
262 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
263 cvar_t r_shadow_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"};
264 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
265 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
266 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
267 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
268 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
269 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
270 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
271 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
274 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
275 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
276 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
277 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
278 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
279 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
280 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
281 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
282 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
283 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
284 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
285 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
286 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
287 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
288 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
289 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
290 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
291 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
292 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
293 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
294 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
295 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
298 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
299 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
300 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
301 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
302 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
303 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
304 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
305 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
306 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
307 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
308 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
309 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
310 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
311 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
312 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
313 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
314 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
315 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
316 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
317 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
318 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
319 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
320 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
322 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
323 #define ATTENTABLESIZE 256
324 // 1D gradient, 2D circle and 3D sphere attenuation textures
325 #define ATTEN1DSIZE 32
326 #define ATTEN2DSIZE 64
327 #define ATTEN3DSIZE 32
329 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
330 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
331 static float r_shadow_attentable[ATTENTABLESIZE+1];
333 rtlight_t *r_shadow_compilingrtlight;
334 static memexpandablearray_t r_shadow_worldlightsarray;
335 dlight_t *r_shadow_selectedlight;
336 dlight_t r_shadow_bufferlight;
337 vec3_t r_editlights_cursorlocation;
339 extern int con_vislines;
341 typedef struct cubemapinfo_s
348 #define MAX_CUBEMAPS 256
349 static int numcubemaps;
350 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
362 // VorteX: custom editor light sprites
363 #define EDLIGHTSPRSIZE 8
364 cachepic_t *r_editlights_sprcursor;
365 cachepic_t *r_editlights_sprlight;
366 cachepic_t *r_editlights_sprnoshadowlight;
367 cachepic_t *r_editlights_sprcubemaplight;
368 cachepic_t *r_editlights_sprcubemapnoshadowlight;
369 cachepic_t *r_editlights_sprselection;
370 extern cvar_t gl_max_size;
372 void R_Shadow_SetShadowMode(void)
374 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4);
375 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
376 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
377 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
378 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
379 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
380 r_shadow_shadowmaplod = -1;
381 r_shadow_shadowmapsize = 0;
382 r_shadow_shadowmapsampler = false;
383 r_shadow_shadowmappcf = 0;
384 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
385 if(r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object)
387 if(r_shadow_shadowmapfilterquality < 0)
389 if(strstr(gl_vendor, "NVIDIA"))
391 r_shadow_shadowmapsampler = gl_support_arb_shadow;
392 r_shadow_shadowmappcf = 1;
394 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
395 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "ATI"))
397 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmapsampler = gl_support_arb_shadow;
403 switch (r_shadow_shadowmapfilterquality)
406 r_shadow_shadowmapsampler = gl_support_arb_shadow;
409 r_shadow_shadowmapsampler = gl_support_arb_shadow;
410 r_shadow_shadowmappcf = 1;
413 r_shadow_shadowmappcf = 1;
416 r_shadow_shadowmappcf = 2;
420 switch (r_shadow_shadowmaptexturetype)
423 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
426 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
429 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
432 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
433 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
434 else if(gl_texturerectangle)
435 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
437 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
443 void R_Shadow_FreeShadowMaps(void)
447 R_Shadow_SetShadowMode();
449 if (r_shadow_fborectangle)
450 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
451 r_shadow_fborectangle = 0;
455 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
458 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
459 if (r_shadow_fbocubeside[i])
460 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
461 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
464 if (r_shadow_shadowmaprectangletexture)
465 R_FreeTexture(r_shadow_shadowmaprectangletexture);
466 r_shadow_shadowmaprectangletexture = NULL;
468 if (r_shadow_shadowmap2dtexture)
469 R_FreeTexture(r_shadow_shadowmap2dtexture);
470 r_shadow_shadowmap2dtexture = NULL;
472 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
473 if (r_shadow_shadowmapcubetexture[i])
474 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
475 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
477 if (r_shadow_shadowmapvsdcttexture)
478 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
479 r_shadow_shadowmapvsdcttexture = NULL;
484 void r_shadow_start(void)
486 // allocate vertex processing arrays
488 r_shadow_attenuationgradienttexture = NULL;
489 r_shadow_attenuation2dtexture = NULL;
490 r_shadow_attenuation3dtexture = NULL;
491 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
492 r_shadow_shadowmaprectangletexture = NULL;
493 r_shadow_shadowmap2dtexture = NULL;
494 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
495 r_shadow_shadowmapvsdcttexture = NULL;
496 r_shadow_shadowmapmaxsize = 0;
497 r_shadow_shadowmapsize = 0;
498 r_shadow_shadowmaplod = 0;
499 r_shadow_shadowmapfilterquality = -1;
500 r_shadow_shadowmaptexturetype = -1;
501 r_shadow_shadowmapdepthbits = 0;
502 r_shadow_shadowmapvsdct = false;
503 r_shadow_shadowmapsampler = false;
504 r_shadow_shadowmappcf = 0;
505 r_shadow_fborectangle = 0;
507 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
509 R_Shadow_FreeShadowMaps();
511 r_shadow_texturepool = NULL;
512 r_shadow_filters_texturepool = NULL;
513 R_Shadow_ValidateCvars();
514 R_Shadow_MakeTextures();
515 maxshadowtriangles = 0;
516 shadowelements = NULL;
517 maxshadowvertices = 0;
518 shadowvertex3f = NULL;
526 shadowmarklist = NULL;
531 shadowsideslist = NULL;
532 r_shadow_buffer_numleafpvsbytes = 0;
533 r_shadow_buffer_visitingleafpvs = NULL;
534 r_shadow_buffer_leafpvs = NULL;
535 r_shadow_buffer_leaflist = NULL;
536 r_shadow_buffer_numsurfacepvsbytes = 0;
537 r_shadow_buffer_surfacepvs = NULL;
538 r_shadow_buffer_surfacelist = NULL;
539 r_shadow_buffer_surfacesides = NULL;
540 r_shadow_buffer_numshadowtrispvsbytes = 0;
541 r_shadow_buffer_shadowtrispvs = NULL;
542 r_shadow_buffer_numlighttrispvsbytes = 0;
543 r_shadow_buffer_lighttrispvs = NULL;
546 void r_shadow_shutdown(void)
549 R_Shadow_UncompileWorldLights();
551 R_Shadow_FreeShadowMaps();
555 r_shadow_attenuationgradienttexture = NULL;
556 r_shadow_attenuation2dtexture = NULL;
557 r_shadow_attenuation3dtexture = NULL;
558 R_FreeTexturePool(&r_shadow_texturepool);
559 R_FreeTexturePool(&r_shadow_filters_texturepool);
560 maxshadowtriangles = 0;
562 Mem_Free(shadowelements);
563 shadowelements = NULL;
565 Mem_Free(shadowvertex3f);
566 shadowvertex3f = NULL;
569 Mem_Free(vertexupdate);
572 Mem_Free(vertexremap);
578 Mem_Free(shadowmark);
581 Mem_Free(shadowmarklist);
582 shadowmarklist = NULL;
587 Mem_Free(shadowsides);
590 Mem_Free(shadowsideslist);
591 shadowsideslist = NULL;
592 r_shadow_buffer_numleafpvsbytes = 0;
593 if (r_shadow_buffer_visitingleafpvs)
594 Mem_Free(r_shadow_buffer_visitingleafpvs);
595 r_shadow_buffer_visitingleafpvs = NULL;
596 if (r_shadow_buffer_leafpvs)
597 Mem_Free(r_shadow_buffer_leafpvs);
598 r_shadow_buffer_leafpvs = NULL;
599 if (r_shadow_buffer_leaflist)
600 Mem_Free(r_shadow_buffer_leaflist);
601 r_shadow_buffer_leaflist = NULL;
602 r_shadow_buffer_numsurfacepvsbytes = 0;
603 if (r_shadow_buffer_surfacepvs)
604 Mem_Free(r_shadow_buffer_surfacepvs);
605 r_shadow_buffer_surfacepvs = NULL;
606 if (r_shadow_buffer_surfacelist)
607 Mem_Free(r_shadow_buffer_surfacelist);
608 r_shadow_buffer_surfacelist = NULL;
609 if (r_shadow_buffer_surfacesides)
610 Mem_Free(r_shadow_buffer_surfacesides);
611 r_shadow_buffer_surfacesides = NULL;
612 r_shadow_buffer_numshadowtrispvsbytes = 0;
613 if (r_shadow_buffer_shadowtrispvs)
614 Mem_Free(r_shadow_buffer_shadowtrispvs);
615 r_shadow_buffer_numlighttrispvsbytes = 0;
616 if (r_shadow_buffer_lighttrispvs)
617 Mem_Free(r_shadow_buffer_lighttrispvs);
620 void r_shadow_newmap(void)
622 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
623 R_Shadow_EditLights_Reload_f();
626 void R_Shadow_Help_f(void)
629 "Documentation on r_shadow system:\n"
631 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
632 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
633 "r_shadow_debuglight : render only this light number (-1 = all)\n"
634 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
635 "r_shadow_gloss2intensity : brightness of forced gloss\n"
636 "r_shadow_glossintensity : brightness of textured gloss\n"
637 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
638 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
639 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
640 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
641 "r_shadow_portallight : use portal visibility for static light precomputation\n"
642 "r_shadow_projectdistance : shadow volume projection distance\n"
643 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
644 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
645 "r_shadow_realtime_world : use high quality world lighting mode\n"
646 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
647 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
648 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
649 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
650 "r_shadow_scissor : use scissor optimization\n"
651 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
652 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
653 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
654 "r_showlighting : useful for performance testing; bright = slow!\n"
655 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
657 "r_shadow_help : this help\n"
661 void R_Shadow_Init(void)
663 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
664 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
665 Cvar_RegisterVariable(&r_shadow_dot3);
666 Cvar_RegisterVariable(&r_shadow_usenormalmap);
667 Cvar_RegisterVariable(&r_shadow_debuglight);
668 Cvar_RegisterVariable(&r_shadow_gloss);
669 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
670 Cvar_RegisterVariable(&r_shadow_glossintensity);
671 Cvar_RegisterVariable(&r_shadow_glossexponent);
672 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
673 Cvar_RegisterVariable(&r_shadow_glossexact);
674 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
675 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
676 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
677 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
678 Cvar_RegisterVariable(&r_shadow_portallight);
679 Cvar_RegisterVariable(&r_shadow_projectdistance);
680 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
681 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
682 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
683 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
684 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
685 Cvar_RegisterVariable(&r_shadow_realtime_world);
686 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
687 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
688 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
689 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
692 Cvar_RegisterVariable(&r_shadow_scissor);
693 Cvar_RegisterVariable(&r_shadow_shadowmapping);
694 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
695 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
701 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
702 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
708 Cvar_RegisterVariable(&r_shadow_culltriangles);
709 Cvar_RegisterVariable(&r_shadow_polygonfactor);
710 Cvar_RegisterVariable(&r_shadow_polygonoffset);
711 Cvar_RegisterVariable(&r_shadow_texture3d);
712 Cvar_RegisterVariable(&r_coronas);
713 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
714 Cvar_RegisterVariable(&r_coronas_occlusionquery);
715 Cvar_RegisterVariable(&gl_flashblend);
716 Cvar_RegisterVariable(&gl_ext_separatestencil);
717 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
718 if (gamemode == GAME_TENEBRAE)
720 Cvar_SetValue("r_shadow_gloss", 2);
721 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
723 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
724 R_Shadow_EditLights_Init();
725 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
726 maxshadowtriangles = 0;
727 shadowelements = NULL;
728 maxshadowvertices = 0;
729 shadowvertex3f = NULL;
737 shadowmarklist = NULL;
742 shadowsideslist = NULL;
743 r_shadow_buffer_numleafpvsbytes = 0;
744 r_shadow_buffer_visitingleafpvs = NULL;
745 r_shadow_buffer_leafpvs = NULL;
746 r_shadow_buffer_leaflist = NULL;
747 r_shadow_buffer_numsurfacepvsbytes = 0;
748 r_shadow_buffer_surfacepvs = NULL;
749 r_shadow_buffer_surfacelist = NULL;
750 r_shadow_buffer_surfacesides = NULL;
751 r_shadow_buffer_shadowtrispvs = NULL;
752 r_shadow_buffer_lighttrispvs = NULL;
753 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
756 matrix4x4_t matrix_attenuationxyz =
759 {0.5, 0.0, 0.0, 0.5},
760 {0.0, 0.5, 0.0, 0.5},
761 {0.0, 0.0, 0.5, 0.5},
766 matrix4x4_t matrix_attenuationz =
769 {0.0, 0.0, 0.5, 0.5},
770 {0.0, 0.0, 0.0, 0.5},
771 {0.0, 0.0, 0.0, 0.5},
776 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
778 numvertices = ((numvertices + 255) & ~255) * vertscale;
779 numtriangles = ((numtriangles + 255) & ~255) * triscale;
780 // make sure shadowelements is big enough for this volume
781 if (maxshadowtriangles < numtriangles)
783 maxshadowtriangles = numtriangles;
785 Mem_Free(shadowelements);
786 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
788 // make sure shadowvertex3f is big enough for this volume
789 if (maxshadowvertices < numvertices)
791 maxshadowvertices = numvertices;
793 Mem_Free(shadowvertex3f);
794 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
798 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
800 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
801 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
802 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
803 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
804 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
806 if (r_shadow_buffer_visitingleafpvs)
807 Mem_Free(r_shadow_buffer_visitingleafpvs);
808 if (r_shadow_buffer_leafpvs)
809 Mem_Free(r_shadow_buffer_leafpvs);
810 if (r_shadow_buffer_leaflist)
811 Mem_Free(r_shadow_buffer_leaflist);
812 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
813 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
814 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
815 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
817 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
819 if (r_shadow_buffer_surfacepvs)
820 Mem_Free(r_shadow_buffer_surfacepvs);
821 if (r_shadow_buffer_surfacelist)
822 Mem_Free(r_shadow_buffer_surfacelist);
823 if (r_shadow_buffer_surfacesides)
824 Mem_Free(r_shadow_buffer_surfacesides);
825 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
826 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
827 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
828 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
830 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
832 if (r_shadow_buffer_shadowtrispvs)
833 Mem_Free(r_shadow_buffer_shadowtrispvs);
834 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
835 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
837 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
839 if (r_shadow_buffer_lighttrispvs)
840 Mem_Free(r_shadow_buffer_lighttrispvs);
841 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
842 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
846 void R_Shadow_PrepareShadowMark(int numtris)
848 // make sure shadowmark is big enough for this volume
849 if (maxshadowmark < numtris)
851 maxshadowmark = numtris;
853 Mem_Free(shadowmark);
855 Mem_Free(shadowmarklist);
856 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
857 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
861 // if shadowmarkcount wrapped we clear the array and adjust accordingly
862 if (shadowmarkcount == 0)
865 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
870 void R_Shadow_PrepareShadowSides(int numtris)
872 if (maxshadowsides < numtris)
874 maxshadowsides = numtris;
876 Mem_Free(shadowsides);
878 Mem_Free(shadowsideslist);
879 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
880 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
885 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)
888 int outtriangles = 0, outvertices = 0;
891 float ratio, direction[3], projectvector[3];
893 if (projectdirection)
894 VectorScale(projectdirection, projectdistance, projectvector);
896 VectorClear(projectvector);
898 // create the vertices
899 if (projectdirection)
901 for (i = 0;i < numshadowmarktris;i++)
903 element = inelement3i + shadowmarktris[i] * 3;
904 for (j = 0;j < 3;j++)
906 if (vertexupdate[element[j]] != vertexupdatenum)
908 vertexupdate[element[j]] = vertexupdatenum;
909 vertexremap[element[j]] = outvertices;
910 vertex = invertex3f + element[j] * 3;
911 // project one copy of the vertex according to projectvector
912 VectorCopy(vertex, outvertex3f);
913 VectorAdd(vertex, projectvector, (outvertex3f + 3));
922 for (i = 0;i < numshadowmarktris;i++)
924 element = inelement3i + shadowmarktris[i] * 3;
925 for (j = 0;j < 3;j++)
927 if (vertexupdate[element[j]] != vertexupdatenum)
929 vertexupdate[element[j]] = vertexupdatenum;
930 vertexremap[element[j]] = outvertices;
931 vertex = invertex3f + element[j] * 3;
932 // project one copy of the vertex to the sphere radius of the light
933 // (FIXME: would projecting it to the light box be better?)
934 VectorSubtract(vertex, projectorigin, direction);
935 ratio = projectdistance / VectorLength(direction);
936 VectorCopy(vertex, outvertex3f);
937 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
945 if (r_shadow_frontsidecasting.integer)
947 for (i = 0;i < numshadowmarktris;i++)
949 int remappedelement[3];
951 const int *neighbortriangle;
953 markindex = shadowmarktris[i] * 3;
954 element = inelement3i + markindex;
955 neighbortriangle = inneighbor3i + markindex;
956 // output the front and back triangles
957 outelement3i[0] = vertexremap[element[0]];
958 outelement3i[1] = vertexremap[element[1]];
959 outelement3i[2] = vertexremap[element[2]];
960 outelement3i[3] = vertexremap[element[2]] + 1;
961 outelement3i[4] = vertexremap[element[1]] + 1;
962 outelement3i[5] = vertexremap[element[0]] + 1;
966 // output the sides (facing outward from this triangle)
967 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
969 remappedelement[0] = vertexremap[element[0]];
970 remappedelement[1] = vertexremap[element[1]];
971 outelement3i[0] = remappedelement[1];
972 outelement3i[1] = remappedelement[0];
973 outelement3i[2] = remappedelement[0] + 1;
974 outelement3i[3] = remappedelement[1];
975 outelement3i[4] = remappedelement[0] + 1;
976 outelement3i[5] = remappedelement[1] + 1;
981 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
983 remappedelement[1] = vertexremap[element[1]];
984 remappedelement[2] = vertexremap[element[2]];
985 outelement3i[0] = remappedelement[2];
986 outelement3i[1] = remappedelement[1];
987 outelement3i[2] = remappedelement[1] + 1;
988 outelement3i[3] = remappedelement[2];
989 outelement3i[4] = remappedelement[1] + 1;
990 outelement3i[5] = remappedelement[2] + 1;
995 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
997 remappedelement[0] = vertexremap[element[0]];
998 remappedelement[2] = vertexremap[element[2]];
999 outelement3i[0] = remappedelement[0];
1000 outelement3i[1] = remappedelement[2];
1001 outelement3i[2] = remappedelement[2] + 1;
1002 outelement3i[3] = remappedelement[0];
1003 outelement3i[4] = remappedelement[2] + 1;
1004 outelement3i[5] = remappedelement[0] + 1;
1013 for (i = 0;i < numshadowmarktris;i++)
1015 int remappedelement[3];
1017 const int *neighbortriangle;
1019 markindex = shadowmarktris[i] * 3;
1020 element = inelement3i + markindex;
1021 neighbortriangle = inneighbor3i + markindex;
1022 // output the front and back triangles
1023 outelement3i[0] = vertexremap[element[2]];
1024 outelement3i[1] = vertexremap[element[1]];
1025 outelement3i[2] = vertexremap[element[0]];
1026 outelement3i[3] = vertexremap[element[0]] + 1;
1027 outelement3i[4] = vertexremap[element[1]] + 1;
1028 outelement3i[5] = vertexremap[element[2]] + 1;
1032 // output the sides (facing outward from this triangle)
1033 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1035 remappedelement[0] = vertexremap[element[0]];
1036 remappedelement[1] = vertexremap[element[1]];
1037 outelement3i[0] = remappedelement[0];
1038 outelement3i[1] = remappedelement[1];
1039 outelement3i[2] = remappedelement[1] + 1;
1040 outelement3i[3] = remappedelement[0];
1041 outelement3i[4] = remappedelement[1] + 1;
1042 outelement3i[5] = remappedelement[0] + 1;
1047 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1049 remappedelement[1] = vertexremap[element[1]];
1050 remappedelement[2] = vertexremap[element[2]];
1051 outelement3i[0] = remappedelement[1];
1052 outelement3i[1] = remappedelement[2];
1053 outelement3i[2] = remappedelement[2] + 1;
1054 outelement3i[3] = remappedelement[1];
1055 outelement3i[4] = remappedelement[2] + 1;
1056 outelement3i[5] = remappedelement[1] + 1;
1061 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1063 remappedelement[0] = vertexremap[element[0]];
1064 remappedelement[2] = vertexremap[element[2]];
1065 outelement3i[0] = remappedelement[2];
1066 outelement3i[1] = remappedelement[0];
1067 outelement3i[2] = remappedelement[0] + 1;
1068 outelement3i[3] = remappedelement[2];
1069 outelement3i[4] = remappedelement[0] + 1;
1070 outelement3i[5] = remappedelement[2] + 1;
1078 *outnumvertices = outvertices;
1079 return outtriangles;
1082 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)
1085 int outtriangles = 0, outvertices = 0;
1087 const float *vertex;
1088 float ratio, direction[3], projectvector[3];
1091 if (projectdirection)
1092 VectorScale(projectdirection, projectdistance, projectvector);
1094 VectorClear(projectvector);
1096 for (i = 0;i < numshadowmarktris;i++)
1098 int remappedelement[3];
1100 const int *neighbortriangle;
1102 markindex = shadowmarktris[i] * 3;
1103 neighbortriangle = inneighbor3i + markindex;
1104 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1105 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1106 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1107 if (side[0] + side[1] + side[2] == 0)
1111 element = inelement3i + markindex;
1113 // create the vertices
1114 for (j = 0;j < 3;j++)
1116 if (side[j] + side[j+1] == 0)
1119 if (vertexupdate[k] != vertexupdatenum)
1121 vertexupdate[k] = vertexupdatenum;
1122 vertexremap[k] = outvertices;
1123 vertex = invertex3f + k * 3;
1124 VectorCopy(vertex, outvertex3f);
1125 if (projectdirection)
1127 // project one copy of the vertex according to projectvector
1128 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1132 // project one copy of the vertex to the sphere radius of the light
1133 // (FIXME: would projecting it to the light box be better?)
1134 VectorSubtract(vertex, projectorigin, direction);
1135 ratio = projectdistance / VectorLength(direction);
1136 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1143 // output the sides (facing outward from this triangle)
1146 remappedelement[0] = vertexremap[element[0]];
1147 remappedelement[1] = vertexremap[element[1]];
1148 outelement3i[0] = remappedelement[1];
1149 outelement3i[1] = remappedelement[0];
1150 outelement3i[2] = remappedelement[0] + 1;
1151 outelement3i[3] = remappedelement[1];
1152 outelement3i[4] = remappedelement[0] + 1;
1153 outelement3i[5] = remappedelement[1] + 1;
1160 remappedelement[1] = vertexremap[element[1]];
1161 remappedelement[2] = vertexremap[element[2]];
1162 outelement3i[0] = remappedelement[2];
1163 outelement3i[1] = remappedelement[1];
1164 outelement3i[2] = remappedelement[1] + 1;
1165 outelement3i[3] = remappedelement[2];
1166 outelement3i[4] = remappedelement[1] + 1;
1167 outelement3i[5] = remappedelement[2] + 1;
1174 remappedelement[0] = vertexremap[element[0]];
1175 remappedelement[2] = vertexremap[element[2]];
1176 outelement3i[0] = remappedelement[0];
1177 outelement3i[1] = remappedelement[2];
1178 outelement3i[2] = remappedelement[2] + 1;
1179 outelement3i[3] = remappedelement[0];
1180 outelement3i[4] = remappedelement[2] + 1;
1181 outelement3i[5] = remappedelement[0] + 1;
1188 *outnumvertices = outvertices;
1189 return outtriangles;
1192 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)
1198 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1200 tend = firsttriangle + numtris;
1201 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1203 // surface box entirely inside light box, no box cull
1204 if (projectdirection)
1206 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1208 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1209 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1210 shadowmarklist[numshadowmark++] = t;
1215 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1216 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1217 shadowmarklist[numshadowmark++] = t;
1222 // surface box not entirely inside light box, cull each triangle
1223 if (projectdirection)
1225 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1227 v[0] = invertex3f + e[0] * 3;
1228 v[1] = invertex3f + e[1] * 3;
1229 v[2] = invertex3f + e[2] * 3;
1230 TriangleNormal(v[0], v[1], v[2], normal);
1231 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1232 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1233 shadowmarklist[numshadowmark++] = t;
1238 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1240 v[0] = invertex3f + e[0] * 3;
1241 v[1] = invertex3f + e[1] * 3;
1242 v[2] = invertex3f + e[2] * 3;
1243 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1244 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1245 shadowmarklist[numshadowmark++] = t;
1251 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1256 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1258 // check if the shadow volume intersects the near plane
1260 // a ray between the eye and light origin may intersect the caster,
1261 // indicating that the shadow may touch the eye location, however we must
1262 // test the near plane (a polygon), not merely the eye location, so it is
1263 // easiest to enlarge the caster bounding shape slightly for this.
1269 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)
1271 int i, tris, outverts;
1272 if (projectdistance < 0.1)
1274 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1277 if (!numverts || !nummarktris)
1279 // make sure shadowelements is big enough for this volume
1280 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1281 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1283 if (maxvertexupdate < numverts)
1285 maxvertexupdate = numverts;
1287 Mem_Free(vertexupdate);
1289 Mem_Free(vertexremap);
1290 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1291 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1292 vertexupdatenum = 0;
1295 if (vertexupdatenum == 0)
1297 vertexupdatenum = 1;
1298 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1299 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1302 for (i = 0;i < nummarktris;i++)
1303 shadowmark[marktris[i]] = shadowmarkcount;
1305 if (r_shadow_compilingrtlight)
1307 // if we're compiling an rtlight, capture the mesh
1308 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1309 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1310 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1311 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1315 // decide which type of shadow to generate and set stencil mode
1316 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1317 // generate the sides or a solid volume, depending on type
1318 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1319 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1321 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1322 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1323 r_refdef.stats.lights_shadowtriangles += tris;
1325 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1326 GL_LockArrays(0, outverts);
1327 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1329 // increment stencil if frontface is infront of depthbuffer
1330 GL_CullFace(r_refdef.view.cullface_front);
1331 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1332 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1333 // decrement stencil if backface is infront of depthbuffer
1334 GL_CullFace(r_refdef.view.cullface_back);
1335 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1337 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1339 // decrement stencil if backface is behind depthbuffer
1340 GL_CullFace(r_refdef.view.cullface_front);
1341 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1342 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1343 // increment stencil if frontface is behind depthbuffer
1344 GL_CullFace(r_refdef.view.cullface_back);
1345 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1347 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1348 GL_LockArrays(0, 0);
1353 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1355 // p1, p2, p3 are in the cubemap's local coordinate system
1356 // bias = border/(size - border)
1359 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1360 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1361 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1362 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1364 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1365 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1366 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1367 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1369 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1370 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1371 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1373 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1374 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1375 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1376 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1378 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1379 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1380 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1381 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1383 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1384 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1385 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1387 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1388 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1389 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1390 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1392 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1393 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1394 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1395 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1397 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1398 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1399 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1404 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1406 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1407 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1410 VectorSubtract(maxs, mins, radius);
1411 VectorScale(radius, 0.5f, radius);
1412 VectorAdd(mins, radius, center);
1413 Matrix4x4_Transform(worldtolight, center, lightcenter);
1414 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1415 VectorSubtract(lightcenter, lightradius, pmin);
1416 VectorAdd(lightcenter, lightradius, pmax);
1418 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1419 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1420 if(ap1 > bias*an1 && ap2 > bias*an2)
1422 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1423 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1424 if(an1 > bias*ap1 && an2 > bias*ap2)
1426 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1427 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1429 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1430 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1431 if(ap1 > bias*an1 && ap2 > bias*an2)
1433 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1434 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1435 if(an1 > bias*ap1 && an2 > bias*ap2)
1437 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1438 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1440 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1441 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1442 if(ap1 > bias*an1 && ap2 > bias*an2)
1444 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1445 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1446 if(an1 > bias*ap1 && an2 > bias*ap2)
1448 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1449 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1454 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1456 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1458 // p is in the cubemap's local coordinate system
1459 // bias = border/(size - border)
1460 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1461 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1462 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1464 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1465 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1466 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1467 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1468 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1469 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1473 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1477 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1478 float scale = (size - 2*border)/size, len;
1479 float bias = border / (float)(size - border), dp, dn, ap, an;
1480 // check if cone enclosing side would cross frustum plane
1481 scale = 2 / (scale*scale + 2);
1482 for (i = 0;i < 5;i++)
1484 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1486 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1487 len = scale*VectorLength2(n);
1488 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1489 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1490 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1492 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1494 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1495 len = scale*VectorLength(n);
1496 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1497 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1498 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1500 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1501 // check if frustum corners/origin cross plane sides
1502 for (i = 0;i < 5;i++)
1504 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1505 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1506 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1507 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1508 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1509 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1510 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1511 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1512 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1513 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1515 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1518 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)
1526 int mask, surfacemask = 0;
1527 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1529 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1530 tend = firsttriangle + numtris;
1531 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1533 // surface box entirely inside light box, no box cull
1534 if (projectdirection)
1536 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1538 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1539 TriangleNormal(v[0], v[1], v[2], normal);
1540 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1542 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1543 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1544 surfacemask |= mask;
1547 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;
1548 shadowsides[numshadowsides] = mask;
1549 shadowsideslist[numshadowsides++] = t;
1556 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1558 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1559 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1561 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1562 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1563 surfacemask |= mask;
1566 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;
1567 shadowsides[numshadowsides] = mask;
1568 shadowsideslist[numshadowsides++] = t;
1576 // surface box not entirely inside light box, cull each triangle
1577 if (projectdirection)
1579 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1581 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1582 TriangleNormal(v[0], v[1], v[2], normal);
1583 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1584 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1586 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1587 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1588 surfacemask |= mask;
1591 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;
1592 shadowsides[numshadowsides] = mask;
1593 shadowsideslist[numshadowsides++] = t;
1600 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1602 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1603 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1604 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1606 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1607 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1608 surfacemask |= mask;
1611 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;
1612 shadowsides[numshadowsides] = mask;
1613 shadowsideslist[numshadowsides++] = t;
1622 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)
1624 int i, j, outtriangles = 0;
1625 int *outelement3i[6];
1626 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1628 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1629 // make sure shadowelements is big enough for this mesh
1630 if (maxshadowtriangles < outtriangles)
1631 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1633 // compute the offset and size of the separate index lists for each cubemap side
1635 for (i = 0;i < 6;i++)
1637 outelement3i[i] = shadowelements + outtriangles * 3;
1638 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1639 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1640 outtriangles += sidetotals[i];
1643 // gather up the (sparse) triangles into separate index lists for each cubemap side
1644 for (i = 0;i < numsidetris;i++)
1646 const int *element = elements + sidetris[i] * 3;
1647 for (j = 0;j < 6;j++)
1649 if (sides[i] & (1 << j))
1651 outelement3i[j][0] = element[0];
1652 outelement3i[j][1] = element[1];
1653 outelement3i[j][2] = element[2];
1654 outelement3i[j] += 3;
1659 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1662 static void R_Shadow_MakeTextures_MakeCorona(void)
1666 unsigned char pixels[32][32][4];
1667 for (y = 0;y < 32;y++)
1669 dy = (y - 15.5f) * (1.0f / 16.0f);
1670 for (x = 0;x < 32;x++)
1672 dx = (x - 15.5f) * (1.0f / 16.0f);
1673 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1674 a = bound(0, a, 255);
1675 pixels[y][x][0] = a;
1676 pixels[y][x][1] = a;
1677 pixels[y][x][2] = a;
1678 pixels[y][x][3] = 255;
1681 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1684 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1686 float dist = sqrt(x*x+y*y+z*z);
1687 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1688 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1689 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1692 static void R_Shadow_MakeTextures(void)
1695 float intensity, dist;
1697 R_FreeTexturePool(&r_shadow_texturepool);
1698 r_shadow_texturepool = R_AllocTexturePool();
1699 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1700 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1701 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1702 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1703 for (x = 0;x <= ATTENTABLESIZE;x++)
1705 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1706 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1707 r_shadow_attentable[x] = bound(0, intensity, 1);
1709 // 1D gradient texture
1710 for (x = 0;x < ATTEN1DSIZE;x++)
1711 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1712 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);
1713 // 2D circle texture
1714 for (y = 0;y < ATTEN2DSIZE;y++)
1715 for (x = 0;x < ATTEN2DSIZE;x++)
1716 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);
1717 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);
1718 // 3D sphere texture
1719 if (r_shadow_texture3d.integer && gl_texture3d)
1721 for (z = 0;z < ATTEN3DSIZE;z++)
1722 for (y = 0;y < ATTEN3DSIZE;y++)
1723 for (x = 0;x < ATTEN3DSIZE;x++)
1724 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));
1725 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);
1728 r_shadow_attenuation3dtexture = NULL;
1731 R_Shadow_MakeTextures_MakeCorona();
1733 // Editor light sprites
1734 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1735 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1736 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1737 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1738 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1739 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1742 void R_Shadow_ValidateCvars(void)
1744 if (r_shadow_texture3d.integer && !gl_texture3d)
1745 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1746 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1747 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1748 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1749 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1752 void R_Shadow_RenderMode_Begin(void)
1758 R_Shadow_ValidateCvars();
1760 if (!r_shadow_attenuation2dtexture
1761 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1762 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1763 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1764 R_Shadow_MakeTextures();
1767 R_Mesh_ColorPointer(NULL, 0, 0);
1768 R_Mesh_ResetTextureState();
1769 GL_BlendFunc(GL_ONE, GL_ZERO);
1770 GL_DepthRange(0, 1);
1771 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1773 GL_DepthMask(false);
1774 GL_Color(0, 0, 0, 1);
1775 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1777 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1779 if (gl_ext_separatestencil.integer)
1781 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1782 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1784 else if (gl_ext_stenciltwoside.integer)
1786 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1787 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1791 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1792 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1795 if (r_glsl.integer && gl_support_fragment_shader)
1796 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1797 else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil)
1798 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1800 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1804 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1805 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1806 r_shadow_drawbuffer = drawbuffer;
1807 r_shadow_readbuffer = readbuffer;
1809 r_shadow_cullface_front = r_refdef.view.cullface_front;
1810 r_shadow_cullface_back = r_refdef.view.cullface_back;
1813 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1815 rsurface.rtlight = rtlight;
1818 void R_Shadow_RenderMode_Reset(void)
1821 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1823 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1825 if (gl_support_ext_framebuffer_object)
1827 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1830 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1831 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1833 R_SetViewport(&r_refdef.view.viewport);
1834 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1835 R_Mesh_ColorPointer(NULL, 0, 0);
1836 R_Mesh_ResetTextureState();
1837 GL_DepthRange(0, 1);
1839 GL_DepthMask(false);
1840 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1841 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1842 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1843 qglStencilMask(~0);CHECKGLERROR
1844 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1845 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1846 r_refdef.view.cullface_front = r_shadow_cullface_front;
1847 r_refdef.view.cullface_back = r_shadow_cullface_back;
1848 GL_CullFace(r_refdef.view.cullface_back);
1849 GL_Color(1, 1, 1, 1);
1850 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1851 GL_BlendFunc(GL_ONE, GL_ZERO);
1852 R_SetupGenericShader(false);
1853 r_shadow_usingshadowmaprect = false;
1854 r_shadow_usingshadowmapcube = false;
1855 r_shadow_usingshadowmap2d = false;
1859 void R_Shadow_ClearStencil(void)
1862 GL_Clear(GL_STENCIL_BUFFER_BIT);
1863 r_refdef.stats.lights_clears++;
1866 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1868 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1869 if (r_shadow_rendermode == mode)
1872 R_Shadow_RenderMode_Reset();
1873 GL_ColorMask(0, 0, 0, 0);
1874 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1875 R_SetupDepthOrShadowShader();
1876 qglDepthFunc(GL_LESS);CHECKGLERROR
1877 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1878 r_shadow_rendermode = mode;
1883 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1884 GL_CullFace(GL_NONE);
1885 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1886 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1888 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1889 GL_CullFace(GL_NONE);
1890 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1891 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1893 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1894 GL_CullFace(GL_NONE);
1895 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1896 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1897 qglStencilMask(~0);CHECKGLERROR
1898 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1899 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1900 qglStencilMask(~0);CHECKGLERROR
1901 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1903 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1904 GL_CullFace(GL_NONE);
1905 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1906 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1907 qglStencilMask(~0);CHECKGLERROR
1908 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1909 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1910 qglStencilMask(~0);CHECKGLERROR
1911 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1916 static void R_Shadow_MakeVSDCT(void)
1918 // maps to a 2x3 texture rectangle with normalized coordinates
1923 // stores abs(dir.xy), offset.xy/2.5
1924 unsigned char data[4*6] =
1926 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1927 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1928 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1929 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1930 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1931 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1933 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1936 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1940 float nearclip, farclip, bias;
1941 r_viewport_t viewport;
1944 maxsize = r_shadow_shadowmapmaxsize;
1945 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1947 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1948 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1949 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1950 r_shadow_shadowmapside = side;
1951 r_shadow_shadowmapsize = size;
1952 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1954 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1955 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1956 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1957 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1959 // complex unrolled cube approach (more flexible)
1960 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1961 R_Shadow_MakeVSDCT();
1962 if (!r_shadow_shadowmap2dtexture)
1965 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1966 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
1967 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1968 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1969 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1970 // render depth into the fbo, do not render color at all
1971 qglDrawBuffer(GL_NONE);CHECKGLERROR
1972 qglReadBuffer(GL_NONE);CHECKGLERROR
1973 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1974 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1976 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1977 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1982 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1983 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1984 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1985 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1987 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1989 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1990 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1991 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1992 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1994 // complex unrolled cube approach (more flexible)
1995 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1996 R_Shadow_MakeVSDCT();
1997 if (!r_shadow_shadowmaprectangletexture)
2000 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2001 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2002 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2003 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2004 // render depth into the fbo, do not render color at all
2005 qglDrawBuffer(GL_NONE);CHECKGLERROR
2006 qglReadBuffer(GL_NONE);CHECKGLERROR
2007 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2008 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2010 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2011 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2016 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2017 r_shadow_shadowmap_texturescale[0] = 1.0f;
2018 r_shadow_shadowmap_texturescale[1] = 1.0f;
2019 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2021 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2023 r_shadow_shadowmap_parameters[0] = 1.0f;
2024 r_shadow_shadowmap_parameters[1] = 1.0f;
2025 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2026 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2028 // simple cube approach
2029 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2032 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2033 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2034 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2035 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
2036 // render depth into the fbo, do not render color at all
2037 qglDrawBuffer(GL_NONE);CHECKGLERROR
2038 qglReadBuffer(GL_NONE);CHECKGLERROR
2039 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2040 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2042 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2043 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2048 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2049 r_shadow_shadowmap_texturescale[0] = 0.0f;
2050 r_shadow_shadowmap_texturescale[1] = 0.0f;
2051 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2054 R_Shadow_RenderMode_Reset();
2057 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2058 R_SetupDepthOrShadowShader();
2062 R_SetupShowDepthShader();
2063 qglClearColor(1,1,1,1);CHECKGLERROR
2066 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2073 R_SetViewport(&viewport);
2074 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2075 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2077 int flipped = (side&1)^(side>>2);
2078 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2079 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2080 GL_CullFace(r_refdef.view.cullface_back);
2082 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2084 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
2087 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2091 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2095 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2096 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2097 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2098 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2101 R_Shadow_RenderMode_Reset();
2102 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2105 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2109 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2110 // only draw light where this geometry was already rendered AND the
2111 // stencil is 128 (values other than this mean shadow)
2112 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2114 r_shadow_rendermode = r_shadow_lightingrendermode;
2115 // do global setup needed for the chosen lighting mode
2116 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2118 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2119 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2123 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2125 r_shadow_usingshadowmap2d = true;
2126 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2129 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2131 r_shadow_usingshadowmaprect = true;
2132 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2135 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2137 r_shadow_usingshadowmapcube = true;
2138 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2142 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2144 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2149 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2150 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2151 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2155 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2158 R_Shadow_RenderMode_Reset();
2159 GL_BlendFunc(GL_ONE, GL_ONE);
2160 GL_DepthRange(0, 1);
2161 GL_DepthTest(r_showshadowvolumes.integer < 2);
2162 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2163 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2164 GL_CullFace(GL_NONE);
2165 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2168 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2171 R_Shadow_RenderMode_Reset();
2172 GL_BlendFunc(GL_ONE, GL_ONE);
2173 GL_DepthRange(0, 1);
2174 GL_DepthTest(r_showlighting.integer < 2);
2175 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2178 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2182 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2183 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2185 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2188 void R_Shadow_RenderMode_End(void)
2191 R_Shadow_RenderMode_Reset();
2192 R_Shadow_RenderMode_ActiveLight(NULL);
2194 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2195 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2198 int bboxedges[12][2] =
2217 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2219 int i, ix1, iy1, ix2, iy2;
2220 float x1, y1, x2, y2;
2222 float vertex[20][3];
2231 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2232 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2233 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2234 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2236 if (!r_shadow_scissor.integer)
2239 // if view is inside the light box, just say yes it's visible
2240 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2243 x1 = y1 = x2 = y2 = 0;
2245 // transform all corners that are infront of the nearclip plane
2246 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2247 plane4f[3] = r_refdef.view.frustum[4].dist;
2249 for (i = 0;i < 8;i++)
2251 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2252 dist[i] = DotProduct4(corner[i], plane4f);
2253 sign[i] = dist[i] > 0;
2256 VectorCopy(corner[i], vertex[numvertices]);
2260 // if some points are behind the nearclip, add clipped edge points to make
2261 // sure that the scissor boundary is complete
2262 if (numvertices > 0 && numvertices < 8)
2264 // add clipped edge points
2265 for (i = 0;i < 12;i++)
2267 j = bboxedges[i][0];
2268 k = bboxedges[i][1];
2269 if (sign[j] != sign[k])
2271 f = dist[j] / (dist[j] - dist[k]);
2272 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2278 // if we have no points to check, the light is behind the view plane
2282 // if we have some points to transform, check what screen area is covered
2283 x1 = y1 = x2 = y2 = 0;
2285 //Con_Printf("%i vertices to transform...\n", numvertices);
2286 for (i = 0;i < numvertices;i++)
2288 VectorCopy(vertex[i], v);
2289 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2290 //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]);
2293 if (x1 > v2[0]) x1 = v2[0];
2294 if (x2 < v2[0]) x2 = v2[0];
2295 if (y1 > v2[1]) y1 = v2[1];
2296 if (y2 < v2[1]) y2 = v2[1];
2305 // now convert the scissor rectangle to integer screen coordinates
2306 ix1 = (int)(x1 - 1.0f);
2307 iy1 = vid.height - (int)(y2 - 1.0f);
2308 ix2 = (int)(x2 + 1.0f);
2309 iy2 = vid.height - (int)(y1 + 1.0f);
2310 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2312 // clamp it to the screen
2313 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2314 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2315 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2316 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2318 // if it is inside out, it's not visible
2319 if (ix2 <= ix1 || iy2 <= iy1)
2322 // the light area is visible, set up the scissor rectangle
2323 r_shadow_lightscissor[0] = ix1;
2324 r_shadow_lightscissor[1] = iy1;
2325 r_shadow_lightscissor[2] = ix2 - ix1;
2326 r_shadow_lightscissor[3] = iy2 - iy1;
2328 r_refdef.stats.lights_scissored++;
2332 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2334 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2335 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2336 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2337 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2338 if (r_textureunits.integer >= 3)
2340 if (VectorLength2(diffusecolor) > 0)
2342 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2344 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2345 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2346 if ((dot = DotProduct(n, v)) < 0)
2348 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2349 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2352 VectorCopy(ambientcolor, color4f);
2353 if (r_refdef.fogenabled)
2356 f = FogPoint_Model(vertex3f);
2357 VectorScale(color4f, f, color4f);
2364 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2366 VectorCopy(ambientcolor, color4f);
2367 if (r_refdef.fogenabled)
2370 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2371 f = FogPoint_Model(vertex3f);
2372 VectorScale(color4f, f, color4f);
2378 else if (r_textureunits.integer >= 2)
2380 if (VectorLength2(diffusecolor) > 0)
2382 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2384 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2385 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2387 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2388 if ((dot = DotProduct(n, v)) < 0)
2390 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2391 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2392 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2393 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2397 color4f[0] = ambientcolor[0] * distintensity;
2398 color4f[1] = ambientcolor[1] * distintensity;
2399 color4f[2] = ambientcolor[2] * distintensity;
2401 if (r_refdef.fogenabled)
2404 f = FogPoint_Model(vertex3f);
2405 VectorScale(color4f, f, color4f);
2409 VectorClear(color4f);
2415 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2417 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2418 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2420 color4f[0] = ambientcolor[0] * distintensity;
2421 color4f[1] = ambientcolor[1] * distintensity;
2422 color4f[2] = ambientcolor[2] * distintensity;
2423 if (r_refdef.fogenabled)
2426 f = FogPoint_Model(vertex3f);
2427 VectorScale(color4f, f, color4f);
2431 VectorClear(color4f);
2438 if (VectorLength2(diffusecolor) > 0)
2440 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2442 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2443 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2445 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2446 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2447 if ((dot = DotProduct(n, v)) < 0)
2449 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2450 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2451 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2452 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2456 color4f[0] = ambientcolor[0] * distintensity;
2457 color4f[1] = ambientcolor[1] * distintensity;
2458 color4f[2] = ambientcolor[2] * distintensity;
2460 if (r_refdef.fogenabled)
2463 f = FogPoint_Model(vertex3f);
2464 VectorScale(color4f, f, color4f);
2468 VectorClear(color4f);
2474 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2476 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2477 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2479 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2480 color4f[0] = ambientcolor[0] * distintensity;
2481 color4f[1] = ambientcolor[1] * distintensity;
2482 color4f[2] = ambientcolor[2] * distintensity;
2483 if (r_refdef.fogenabled)
2486 f = FogPoint_Model(vertex3f);
2487 VectorScale(color4f, f, color4f);
2491 VectorClear(color4f);
2498 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2500 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2503 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2504 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2505 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2506 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2507 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2509 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2511 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2512 // the cubemap normalizes this for us
2513 out3f[0] = DotProduct(svector3f, lightdir);
2514 out3f[1] = DotProduct(tvector3f, lightdir);
2515 out3f[2] = DotProduct(normal3f, lightdir);
2519 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2522 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2523 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2524 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2525 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2526 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2527 float lightdir[3], eyedir[3], halfdir[3];
2528 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2530 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2531 VectorNormalize(lightdir);
2532 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2533 VectorNormalize(eyedir);
2534 VectorAdd(lightdir, eyedir, halfdir);
2535 // the cubemap normalizes this for us
2536 out3f[0] = DotProduct(svector3f, halfdir);
2537 out3f[1] = DotProduct(tvector3f, halfdir);
2538 out3f[2] = DotProduct(normal3f, halfdir);
2542 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)
2544 // used to display how many times a surface is lit for level design purposes
2545 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2548 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)
2550 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2551 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2552 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2553 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2555 R_Mesh_ColorPointer(NULL, 0, 0);
2556 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2557 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2558 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2559 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2560 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2561 if (rsurface.texture->backgroundcurrentskinframe)
2563 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2564 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2565 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2566 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2568 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2569 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2570 if(rsurface.texture->colormapping)
2572 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2573 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2575 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2576 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2577 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2578 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2579 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2580 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2582 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2584 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2585 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2587 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2591 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)
2593 // shared final code for all the dot3 layers
2595 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2596 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2598 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2599 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2603 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)
2606 // colorscale accounts for how much we multiply the brightness
2609 // mult is how many times the final pass of the lighting will be
2610 // performed to get more brightness than otherwise possible.
2612 // Limit mult to 64 for sanity sake.
2614 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2616 // 3 3D combine path (Geforce3, Radeon 8500)
2617 memset(&m, 0, sizeof(m));
2618 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2619 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2620 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2621 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2622 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2623 m.tex[1] = R_GetTexture(basetexture);
2624 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2625 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2626 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2627 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2628 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2629 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2630 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2631 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2632 m.texmatrix[2] = rsurface.entitytolight;
2633 GL_BlendFunc(GL_ONE, GL_ONE);
2635 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2637 // 2 3D combine path (Geforce3, original Radeon)
2638 memset(&m, 0, sizeof(m));
2639 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2640 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2641 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2642 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2643 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2644 m.tex[1] = R_GetTexture(basetexture);
2645 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2646 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2647 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2648 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2649 GL_BlendFunc(GL_ONE, GL_ONE);
2651 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2653 // 4 2D combine path (Geforce3, Radeon 8500)
2654 memset(&m, 0, sizeof(m));
2655 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2656 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2657 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2658 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2659 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2660 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2661 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2662 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2663 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2664 m.texmatrix[1] = rsurface.entitytoattenuationz;
2665 m.tex[2] = R_GetTexture(basetexture);
2666 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2667 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2668 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2669 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2670 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2672 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2673 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2674 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2675 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2676 m.texmatrix[3] = rsurface.entitytolight;
2678 GL_BlendFunc(GL_ONE, GL_ONE);
2680 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2682 // 3 2D combine path (Geforce3, original Radeon)
2683 memset(&m, 0, sizeof(m));
2684 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2685 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2686 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2687 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2688 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2689 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2690 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2691 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2692 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2693 m.texmatrix[1] = rsurface.entitytoattenuationz;
2694 m.tex[2] = R_GetTexture(basetexture);
2695 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2696 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2697 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2698 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2699 GL_BlendFunc(GL_ONE, GL_ONE);
2703 // 2/2/2 2D combine path (any dot3 card)
2704 memset(&m, 0, sizeof(m));
2705 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2706 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2707 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2708 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2709 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2710 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2711 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2712 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2713 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2714 m.texmatrix[1] = rsurface.entitytoattenuationz;
2715 R_Mesh_TextureState(&m);
2716 GL_ColorMask(0,0,0,1);
2717 GL_BlendFunc(GL_ONE, GL_ZERO);
2718 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2721 memset(&m, 0, sizeof(m));
2722 m.tex[0] = R_GetTexture(basetexture);
2723 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2724 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2725 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2726 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2727 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2729 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2730 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2731 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2732 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2733 m.texmatrix[1] = rsurface.entitytolight;
2735 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2737 // this final code is shared
2738 R_Mesh_TextureState(&m);
2739 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);
2742 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)
2745 // colorscale accounts for how much we multiply the brightness
2748 // mult is how many times the final pass of the lighting will be
2749 // performed to get more brightness than otherwise possible.
2751 // Limit mult to 64 for sanity sake.
2753 // generate normalization cubemap texcoords
2754 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2755 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2757 // 3/2 3D combine path (Geforce3, Radeon 8500)
2758 memset(&m, 0, sizeof(m));
2759 m.tex[0] = R_GetTexture(normalmaptexture);
2760 m.texcombinergb[0] = GL_REPLACE;
2761 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2762 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2763 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2764 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2765 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2766 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2767 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2768 m.pointer_texcoord_bufferobject[1] = 0;
2769 m.pointer_texcoord_bufferoffset[1] = 0;
2770 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2771 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2772 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2773 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2774 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2775 R_Mesh_TextureState(&m);
2776 GL_ColorMask(0,0,0,1);
2777 GL_BlendFunc(GL_ONE, GL_ZERO);
2778 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2781 memset(&m, 0, sizeof(m));
2782 m.tex[0] = R_GetTexture(basetexture);
2783 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2784 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2785 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2786 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2787 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2789 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2790 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2791 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2792 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2793 m.texmatrix[1] = rsurface.entitytolight;
2795 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2797 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2799 // 1/2/2 3D combine path (original Radeon)
2800 memset(&m, 0, sizeof(m));
2801 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2802 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2803 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2804 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2805 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2806 R_Mesh_TextureState(&m);
2807 GL_ColorMask(0,0,0,1);
2808 GL_BlendFunc(GL_ONE, GL_ZERO);
2809 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2812 memset(&m, 0, sizeof(m));
2813 m.tex[0] = R_GetTexture(normalmaptexture);
2814 m.texcombinergb[0] = GL_REPLACE;
2815 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2816 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2817 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2818 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2819 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2820 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2821 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2822 m.pointer_texcoord_bufferobject[1] = 0;
2823 m.pointer_texcoord_bufferoffset[1] = 0;
2824 R_Mesh_TextureState(&m);
2825 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2826 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2829 memset(&m, 0, sizeof(m));
2830 m.tex[0] = R_GetTexture(basetexture);
2831 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2832 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2833 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2834 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2835 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2837 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2838 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2839 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2840 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2841 m.texmatrix[1] = rsurface.entitytolight;
2843 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2845 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2847 // 2/2 3D combine path (original Radeon)
2848 memset(&m, 0, sizeof(m));
2849 m.tex[0] = R_GetTexture(normalmaptexture);
2850 m.texcombinergb[0] = GL_REPLACE;
2851 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2852 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2853 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2854 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2855 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2856 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2857 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2858 m.pointer_texcoord_bufferobject[1] = 0;
2859 m.pointer_texcoord_bufferoffset[1] = 0;
2860 R_Mesh_TextureState(&m);
2861 GL_ColorMask(0,0,0,1);
2862 GL_BlendFunc(GL_ONE, GL_ZERO);
2863 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2866 memset(&m, 0, sizeof(m));
2867 m.tex[0] = R_GetTexture(basetexture);
2868 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2869 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2870 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2871 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2872 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2873 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2874 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2875 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2876 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2877 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2879 else if (r_textureunits.integer >= 4)
2881 // 4/2 2D combine path (Geforce3, Radeon 8500)
2882 memset(&m, 0, sizeof(m));
2883 m.tex[0] = R_GetTexture(normalmaptexture);
2884 m.texcombinergb[0] = GL_REPLACE;
2885 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2886 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2887 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2888 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2889 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2890 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2891 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2892 m.pointer_texcoord_bufferobject[1] = 0;
2893 m.pointer_texcoord_bufferoffset[1] = 0;
2894 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2895 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2896 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2897 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2898 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2899 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2900 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2901 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2902 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2903 m.texmatrix[3] = rsurface.entitytoattenuationz;
2904 R_Mesh_TextureState(&m);
2905 GL_ColorMask(0,0,0,1);
2906 GL_BlendFunc(GL_ONE, GL_ZERO);
2907 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2910 memset(&m, 0, sizeof(m));
2911 m.tex[0] = R_GetTexture(basetexture);
2912 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2913 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2914 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2915 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2916 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2918 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2919 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2920 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2921 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2922 m.texmatrix[1] = rsurface.entitytolight;
2924 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2928 // 2/2/2 2D combine path (any dot3 card)
2929 memset(&m, 0, sizeof(m));
2930 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2931 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2932 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2933 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2934 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2935 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2936 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2937 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2938 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2939 m.texmatrix[1] = rsurface.entitytoattenuationz;
2940 R_Mesh_TextureState(&m);
2941 GL_ColorMask(0,0,0,1);
2942 GL_BlendFunc(GL_ONE, GL_ZERO);
2943 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2946 memset(&m, 0, sizeof(m));
2947 m.tex[0] = R_GetTexture(normalmaptexture);
2948 m.texcombinergb[0] = GL_REPLACE;
2949 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2950 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2951 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2952 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2953 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2954 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2955 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2956 m.pointer_texcoord_bufferobject[1] = 0;
2957 m.pointer_texcoord_bufferoffset[1] = 0;
2958 R_Mesh_TextureState(&m);
2959 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2960 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2963 memset(&m, 0, sizeof(m));
2964 m.tex[0] = R_GetTexture(basetexture);
2965 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2966 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2967 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2968 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2969 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2971 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2972 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2973 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2974 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2975 m.texmatrix[1] = rsurface.entitytolight;
2977 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2979 // this final code is shared
2980 R_Mesh_TextureState(&m);
2981 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);
2984 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)
2986 float glossexponent;
2988 // FIXME: detect blendsquare!
2989 //if (!gl_support_blendsquare)
2992 // generate normalization cubemap texcoords
2993 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2994 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2996 // 2/0/0/1/2 3D combine blendsquare path
2997 memset(&m, 0, sizeof(m));
2998 m.tex[0] = R_GetTexture(normalmaptexture);
2999 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3000 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3001 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3002 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3003 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3004 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3005 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3006 m.pointer_texcoord_bufferobject[1] = 0;
3007 m.pointer_texcoord_bufferoffset[1] = 0;
3008 R_Mesh_TextureState(&m);
3009 GL_ColorMask(0,0,0,1);
3010 // this squares the result
3011 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3012 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3014 // second and third pass
3015 R_Mesh_ResetTextureState();
3016 // square alpha in framebuffer a few times to make it shiny
3017 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3018 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3019 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3022 memset(&m, 0, sizeof(m));
3023 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3024 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3025 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3026 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3027 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3028 R_Mesh_TextureState(&m);
3029 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3030 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3033 memset(&m, 0, sizeof(m));
3034 m.tex[0] = R_GetTexture(glosstexture);
3035 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3036 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3037 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3038 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3039 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3041 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3042 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3043 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3044 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3045 m.texmatrix[1] = rsurface.entitytolight;
3047 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3049 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3051 // 2/0/0/2 3D combine blendsquare path
3052 memset(&m, 0, sizeof(m));
3053 m.tex[0] = R_GetTexture(normalmaptexture);
3054 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3055 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3056 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3057 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3058 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3059 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3060 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3061 m.pointer_texcoord_bufferobject[1] = 0;
3062 m.pointer_texcoord_bufferoffset[1] = 0;
3063 R_Mesh_TextureState(&m);
3064 GL_ColorMask(0,0,0,1);
3065 // this squares the result
3066 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3067 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3069 // second and third pass
3070 R_Mesh_ResetTextureState();
3071 // square alpha in framebuffer a few times to make it shiny
3072 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3073 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3074 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3077 memset(&m, 0, sizeof(m));
3078 m.tex[0] = R_GetTexture(glosstexture);
3079 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3080 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3081 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3082 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3083 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3084 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3085 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3086 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3087 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3088 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3092 // 2/0/0/2/2 2D combine blendsquare path
3093 memset(&m, 0, sizeof(m));
3094 m.tex[0] = R_GetTexture(normalmaptexture);
3095 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3096 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3097 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3098 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3099 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3100 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3101 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3102 m.pointer_texcoord_bufferobject[1] = 0;
3103 m.pointer_texcoord_bufferoffset[1] = 0;
3104 R_Mesh_TextureState(&m);
3105 GL_ColorMask(0,0,0,1);
3106 // this squares the result
3107 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3108 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3110 // second and third pass
3111 R_Mesh_ResetTextureState();
3112 // square alpha in framebuffer a few times to make it shiny
3113 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3114 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3115 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3118 memset(&m, 0, sizeof(m));
3119 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3120 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3121 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3122 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3123 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3124 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3125 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3126 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3127 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3128 m.texmatrix[1] = rsurface.entitytoattenuationz;
3129 R_Mesh_TextureState(&m);
3130 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3131 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3134 memset(&m, 0, sizeof(m));
3135 m.tex[0] = R_GetTexture(glosstexture);
3136 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3137 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3138 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3139 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3140 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3142 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3143 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3144 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3145 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3146 m.texmatrix[1] = rsurface.entitytolight;
3148 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3150 // this final code is shared
3151 R_Mesh_TextureState(&m);
3152 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);
3155 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)
3157 // ARB path (any Geforce, any Radeon)
3158 qboolean doambient = ambientscale > 0;
3159 qboolean dodiffuse = diffusescale > 0;
3160 qboolean dospecular = specularscale > 0;
3161 if (!doambient && !dodiffuse && !dospecular)
3163 R_Mesh_ColorPointer(NULL, 0, 0);
3165 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3167 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3171 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3173 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3178 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3180 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3183 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3186 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3193 int newnumtriangles;
3197 int maxtriangles = 4096;
3198 int newelements[4096*3];
3199 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3200 for (renders = 0;renders < 64;renders++)
3205 newnumtriangles = 0;
3207 // due to low fillrate on the cards this vertex lighting path is
3208 // designed for, we manually cull all triangles that do not
3209 // contain a lit vertex
3210 // this builds batches of triangles from multiple surfaces and
3211 // renders them at once
3212 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3214 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3216 if (newnumtriangles)
3218 newfirstvertex = min(newfirstvertex, e[0]);
3219 newlastvertex = max(newlastvertex, e[0]);
3223 newfirstvertex = e[0];
3224 newlastvertex = e[0];
3226 newfirstvertex = min(newfirstvertex, e[1]);
3227 newlastvertex = max(newlastvertex, e[1]);
3228 newfirstvertex = min(newfirstvertex, e[2]);
3229 newlastvertex = max(newlastvertex, e[2]);
3235 if (newnumtriangles >= maxtriangles)
3237 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3238 newnumtriangles = 0;
3244 if (newnumtriangles >= 1)
3246 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3249 // if we couldn't find any lit triangles, exit early
3252 // now reduce the intensity for the next overbright pass
3253 // we have to clamp to 0 here incase the drivers have improper
3254 // handling of negative colors
3255 // (some old drivers even have improper handling of >1 color)
3257 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3259 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3261 c[0] = max(0, c[0] - 1);
3262 c[1] = max(0, c[1] - 1);
3263 c[2] = max(0, c[2] - 1);
3275 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)
3277 // OpenGL 1.1 path (anything)
3278 float ambientcolorbase[3], diffusecolorbase[3];
3279 float ambientcolorpants[3], diffusecolorpants[3];
3280 float ambientcolorshirt[3], diffusecolorshirt[3];
3282 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3283 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3284 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3285 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3286 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3287 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3288 memset(&m, 0, sizeof(m));
3289 m.tex[0] = R_GetTexture(basetexture);
3290 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3291 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3292 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3293 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3294 if (r_textureunits.integer >= 2)
3297 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3298 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3299 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3300 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3301 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3302 if (r_textureunits.integer >= 3)
3304 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3305 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3306 m.texmatrix[2] = rsurface.entitytoattenuationz;
3307 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3308 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3309 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3312 R_Mesh_TextureState(&m);
3313 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3314 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3317 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3318 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3322 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3323 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3327 extern cvar_t gl_lightmaps;
3328 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)
3330 float ambientscale, diffusescale, specularscale;
3331 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3333 // calculate colors to render this texture with
3334 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3335 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3336 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3337 ambientscale = rsurface.rtlight->ambientscale;
3338 diffusescale = rsurface.rtlight->diffusescale;
3339 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3340 if (!r_shadow_usenormalmap.integer)
3342 ambientscale += 1.0f * diffusescale;
3346 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3348 RSurf_SetupDepthAndCulling();
3349 nmap = rsurface.texture->currentskinframe->nmap;
3350 if (gl_lightmaps.integer)
3351 nmap = r_texture_blanknormalmap;
3352 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3354 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3355 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3358 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3359 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3360 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3363 VectorClear(lightcolorpants);
3366 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3367 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3368 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3371 VectorClear(lightcolorshirt);
3372 switch (r_shadow_rendermode)
3374 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3375 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3376 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);
3378 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3379 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);
3381 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3382 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);
3384 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3385 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);
3388 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3394 switch (r_shadow_rendermode)
3396 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3397 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3398 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);
3400 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3401 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);
3403 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3404 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);
3406 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3407 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);
3410 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3416 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)
3418 matrix4x4_t tempmatrix = *matrix;
3419 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3421 // if this light has been compiled before, free the associated data
3422 R_RTLight_Uncompile(rtlight);
3424 // clear it completely to avoid any lingering data
3425 memset(rtlight, 0, sizeof(*rtlight));
3427 // copy the properties
3428 rtlight->matrix_lighttoworld = tempmatrix;
3429 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3430 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3431 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3432 VectorCopy(color, rtlight->color);
3433 rtlight->cubemapname[0] = 0;
3434 if (cubemapname && cubemapname[0])
3435 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3436 rtlight->shadow = shadow;
3437 rtlight->corona = corona;
3438 rtlight->style = style;
3439 rtlight->isstatic = isstatic;
3440 rtlight->coronasizescale = coronasizescale;
3441 rtlight->ambientscale = ambientscale;
3442 rtlight->diffusescale = diffusescale;
3443 rtlight->specularscale = specularscale;
3444 rtlight->flags = flags;
3446 // compute derived data
3447 //rtlight->cullradius = rtlight->radius;
3448 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3449 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3450 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3451 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3452 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3453 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3454 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3457 // compiles rtlight geometry
3458 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3459 void R_RTLight_Compile(rtlight_t *rtlight)
3462 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3463 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3464 entity_render_t *ent = r_refdef.scene.worldentity;
3465 dp_model_t *model = r_refdef.scene.worldmodel;
3466 unsigned char *data;
3469 // compile the light
3470 rtlight->compiled = true;
3471 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3472 rtlight->static_numleafs = 0;
3473 rtlight->static_numleafpvsbytes = 0;
3474 rtlight->static_leaflist = NULL;
3475 rtlight->static_leafpvs = NULL;
3476 rtlight->static_numsurfaces = 0;
3477 rtlight->static_surfacelist = NULL;
3478 rtlight->static_shadowmap_receivers = 0x3F;
3479 rtlight->static_shadowmap_casters = 0x3F;
3480 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3481 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3482 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3483 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3484 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3485 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3487 if (model && model->GetLightInfo)
3489 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3490 r_shadow_compilingrtlight = rtlight;
3491 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);
3492 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);
3493 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3494 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3495 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3496 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3497 rtlight->static_numsurfaces = numsurfaces;
3498 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3499 rtlight->static_numleafs = numleafs;
3500 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3501 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3502 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3503 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3504 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3505 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3506 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3507 if (rtlight->static_numsurfaces)
3508 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3509 if (rtlight->static_numleafs)
3510 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3511 if (rtlight->static_numleafpvsbytes)
3512 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3513 if (rtlight->static_numshadowtrispvsbytes)
3514 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3515 if (rtlight->static_numlighttrispvsbytes)
3516 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3517 switch (rtlight->shadowmode)
3519 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3520 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3521 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3522 if (model->CompileShadowMap && rtlight->shadow)
3523 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3526 if (model->CompileShadowVolume && rtlight->shadow)
3527 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3530 // now we're done compiling the rtlight
3531 r_shadow_compilingrtlight = NULL;
3535 // use smallest available cullradius - box radius or light radius
3536 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3537 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3539 shadowzpasstris = 0;
3540 if (rtlight->static_meshchain_shadow_zpass)
3541 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3542 shadowzpasstris += mesh->numtriangles;
3544 shadowzfailtris = 0;
3545 if (rtlight->static_meshchain_shadow_zfail)
3546 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3547 shadowzfailtris += mesh->numtriangles;
3550 if (rtlight->static_numlighttrispvsbytes)
3551 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3552 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3556 if (rtlight->static_numlighttrispvsbytes)
3557 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3558 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3561 if (developer.integer >= 10)
3562 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);
3565 void R_RTLight_Uncompile(rtlight_t *rtlight)
3567 if (rtlight->compiled)
3569 if (rtlight->static_meshchain_shadow_zpass)
3570 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3571 rtlight->static_meshchain_shadow_zpass = NULL;
3572 if (rtlight->static_meshchain_shadow_zfail)
3573 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3574 rtlight->static_meshchain_shadow_zfail = NULL;
3575 if (rtlight->static_meshchain_shadow_shadowmap)
3576 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3577 rtlight->static_meshchain_shadow_shadowmap = NULL;
3578 // these allocations are grouped
3579 if (rtlight->static_surfacelist)
3580 Mem_Free(rtlight->static_surfacelist);
3581 rtlight->static_numleafs = 0;
3582 rtlight->static_numleafpvsbytes = 0;
3583 rtlight->static_leaflist = NULL;
3584 rtlight->static_leafpvs = NULL;
3585 rtlight->static_numsurfaces = 0;
3586 rtlight->static_surfacelist = NULL;
3587 rtlight->static_numshadowtrispvsbytes = 0;
3588 rtlight->static_shadowtrispvs = NULL;
3589 rtlight->static_numlighttrispvsbytes = 0;
3590 rtlight->static_lighttrispvs = NULL;
3591 rtlight->compiled = false;
3595 void R_Shadow_UncompileWorldLights(void)
3599 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3600 for (lightindex = 0;lightindex < range;lightindex++)
3602 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3605 R_RTLight_Uncompile(&light->rtlight);
3609 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3613 // reset the count of frustum planes
3614 // see rsurface.rtlight_frustumplanes definition for how much this array
3616 rsurface.rtlight_numfrustumplanes = 0;
3618 // haven't implemented a culling path for ortho rendering
3619 if (!r_refdef.view.useperspective)
3621 // check if the light is on screen and copy the 4 planes if it is
3622 for (i = 0;i < 4;i++)
3623 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3626 for (i = 0;i < 4;i++)
3627 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3632 // generate a deformed frustum that includes the light origin, this is
3633 // used to cull shadow casting surfaces that can not possibly cast a
3634 // shadow onto the visible light-receiving surfaces, which can be a
3637 // if the light origin is onscreen the result will be 4 planes exactly
3638 // if the light origin is offscreen on only one axis the result will
3639 // be exactly 5 planes (split-side case)
3640 // if the light origin is offscreen on two axes the result will be
3641 // exactly 4 planes (stretched corner case)
3642 for (i = 0;i < 4;i++)
3644 // quickly reject standard frustum planes that put the light
3645 // origin outside the frustum
3646 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3649 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3651 // if all the standard frustum planes were accepted, the light is onscreen
3652 // otherwise we need to generate some more planes below...
3653 if (rsurface.rtlight_numfrustumplanes < 4)
3655 // at least one of the stock frustum planes failed, so we need to
3656 // create one or two custom planes to enclose the light origin
3657 for (i = 0;i < 4;i++)
3659 // create a plane using the view origin and light origin, and a
3660 // single point from the frustum corner set
3661 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3662 VectorNormalize(plane.normal);
3663 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3664 // see if this plane is backwards and flip it if so
3665 for (j = 0;j < 4;j++)
3666 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3670 VectorNegate(plane.normal, plane.normal);
3672 // flipped plane, test again to see if it is now valid
3673 for (j = 0;j < 4;j++)
3674 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3676 // if the plane is still not valid, then it is dividing the
3677 // frustum and has to be rejected
3681 // we have created a valid plane, compute extra info
3682 PlaneClassify(&plane);
3684 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3686 // if we've found 5 frustum planes then we have constructed a
3687 // proper split-side case and do not need to keep searching for
3688 // planes to enclose the light origin
3689 if (rsurface.rtlight_numfrustumplanes == 5)
3697 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3699 plane = rsurface.rtlight_frustumplanes[i];
3700 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));
3705 // now add the light-space box planes if the light box is rotated, as any
3706 // caster outside the oriented light box is irrelevant (even if it passed
3707 // the worldspace light box, which is axial)
3708 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3710 for (i = 0;i < 6;i++)
3714 v[i >> 1] = (i & 1) ? -1 : 1;
3715 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3716 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3717 plane.dist = VectorNormalizeLength(plane.normal);
3718 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3719 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3725 // add the world-space reduced box planes
3726 for (i = 0;i < 6;i++)
3728 VectorClear(plane.normal);
3729 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3730 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3731 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3740 // reduce all plane distances to tightly fit the rtlight cull box, which
3742 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3743 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3744 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3745 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3746 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3747 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3748 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3749 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3750 oldnum = rsurface.rtlight_numfrustumplanes;
3751 rsurface.rtlight_numfrustumplanes = 0;
3752 for (j = 0;j < oldnum;j++)
3754 // find the nearest point on the box to this plane
3755 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3756 for (i = 1;i < 8;i++)
3758 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3759 if (bestdist > dist)
3762 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);
3763 // if the nearest point is near or behind the plane, we want this
3764 // plane, otherwise the plane is useless as it won't cull anything
3765 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3767 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3768 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3775 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3779 RSurf_ActiveWorldEntity();
3781 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3784 GL_CullFace(GL_NONE);
3785 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3786 for (;mesh;mesh = mesh->next)
3788 if (!mesh->sidetotals[r_shadow_shadowmapside])
3790 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3791 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3792 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3796 else if (r_refdef.scene.worldentity->model)
3797 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);
3799 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3802 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3807 int surfacelistindex;
3808 msurface_t *surface;
3810 RSurf_ActiveWorldEntity();
3812 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3815 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3816 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3817 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3818 for (;mesh;mesh = mesh->next)
3820 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3821 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3822 GL_LockArrays(0, mesh->numverts);
3823 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3825 // increment stencil if frontface is infront of depthbuffer
3826 GL_CullFace(r_refdef.view.cullface_back);
3827 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3828 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3829 // decrement stencil if backface is infront of depthbuffer
3830 GL_CullFace(r_refdef.view.cullface_front);
3831 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3833 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3835 // decrement stencil if backface is behind depthbuffer
3836 GL_CullFace(r_refdef.view.cullface_front);
3837 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3838 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3839 // increment stencil if frontface is behind depthbuffer
3840 GL_CullFace(r_refdef.view.cullface_back);
3841 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3843 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3844 GL_LockArrays(0, 0);
3848 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3850 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3851 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3853 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3854 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3855 if (CHECKPVSBIT(trispvs, t))
3856 shadowmarklist[numshadowmark++] = t;
3858 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);
3860 else if (numsurfaces)
3861 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3863 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3866 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3868 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3869 vec_t relativeshadowradius;
3870 RSurf_ActiveModelEntity(ent, false, false);
3871 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3872 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3873 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3874 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3875 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3876 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3877 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3878 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3879 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3881 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3884 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3885 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3888 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3890 // set up properties for rendering light onto this entity
3891 RSurf_ActiveModelEntity(ent, true, true);
3892 GL_AlphaTest(false);
3893 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3894 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3895 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3896 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3897 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3898 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3901 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3903 if (!r_refdef.scene.worldmodel->DrawLight)
3906 // set up properties for rendering light onto this entity
3907 RSurf_ActiveWorldEntity();
3908 GL_AlphaTest(false);
3909 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3910 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3911 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3912 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3913 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3914 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3916 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3918 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3921 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3923 dp_model_t *model = ent->model;
3924 if (!model->DrawLight)
3927 R_Shadow_SetupEntityLight(ent);
3929 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3931 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3934 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3938 int numleafs, numsurfaces;
3939 int *leaflist, *surfacelist;
3940 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3941 int numlightentities;
3942 int numlightentities_noselfshadow;
3943 int numshadowentities;
3944 int numshadowentities_noselfshadow;
3945 static entity_render_t *lightentities[MAX_EDICTS];
3946 static entity_render_t *shadowentities[MAX_EDICTS];
3947 static unsigned char entitysides[MAX_EDICTS];
3948 int lightentities_noselfshadow;
3949 int shadowentities_noselfshadow;
3950 vec3_t nearestpoint;
3952 qboolean castshadows;
3955 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3956 // skip lights that are basically invisible (color 0 0 0)
3957 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3960 // loading is done before visibility checks because loading should happen
3961 // all at once at the start of a level, not when it stalls gameplay.
3962 // (especially important to benchmarks)
3964 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3966 if (rtlight->compiled)
3967 R_RTLight_Uncompile(rtlight);
3968 R_RTLight_Compile(rtlight);
3972 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3974 // look up the light style value at this time
3975 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3976 VectorScale(rtlight->color, f, rtlight->currentcolor);
3978 if (rtlight->selected)
3980 f = 2 + sin(realtime * M_PI * 4.0);
3981 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3985 // if lightstyle is currently off, don't draw the light
3986 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3989 // if the light box is offscreen, skip it
3990 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3993 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3994 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3996 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3998 // compiled light, world available and can receive realtime lighting
3999 // retrieve leaf information
4000 numleafs = rtlight->static_numleafs;
4001 leaflist = rtlight->static_leaflist;
4002 leafpvs = rtlight->static_leafpvs;
4003 numsurfaces = rtlight->static_numsurfaces;
4004 surfacelist = rtlight->static_surfacelist;
4005 surfacesides = NULL;
4006 shadowtrispvs = rtlight->static_shadowtrispvs;
4007 lighttrispvs = rtlight->static_lighttrispvs;
4009 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4011 // dynamic light, world available and can receive realtime lighting
4012 // calculate lit surfaces and leafs
4013 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);
4014 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);
4015 leaflist = r_shadow_buffer_leaflist;
4016 leafpvs = r_shadow_buffer_leafpvs;
4017 surfacelist = r_shadow_buffer_surfacelist;
4018 surfacesides = r_shadow_buffer_surfacesides;
4019 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4020 lighttrispvs = r_shadow_buffer_lighttrispvs;
4021 // if the reduced leaf bounds are offscreen, skip it
4022 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4033 surfacesides = NULL;
4034 shadowtrispvs = NULL;
4035 lighttrispvs = NULL;
4037 // check if light is illuminating any visible leafs
4040 for (i = 0;i < numleafs;i++)
4041 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4046 // set up a scissor rectangle for this light
4047 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4050 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4052 // make a list of lit entities and shadow casting entities
4053 numlightentities = 0;
4054 numlightentities_noselfshadow = 0;
4055 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4056 numshadowentities = 0;
4057 numshadowentities_noselfshadow = 0;
4058 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4060 // add dynamic entities that are lit by the light
4061 if (r_drawentities.integer)
4063 for (i = 0;i < r_refdef.scene.numentities;i++)
4066 entity_render_t *ent = r_refdef.scene.entities[i];
4068 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4070 // skip the object entirely if it is not within the valid
4071 // shadow-casting region (which includes the lit region)
4072 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4074 if (!(model = ent->model))
4076 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4078 // this entity wants to receive light, is visible, and is
4079 // inside the light box
4080 // TODO: check if the surfaces in the model can receive light
4081 // so now check if it's in a leaf seen by the light
4082 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))
4084 if (ent->flags & RENDER_NOSELFSHADOW)
4085 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4087 lightentities[numlightentities++] = ent;
4088 // since it is lit, it probably also casts a shadow...
4089 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4090 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4091 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4093 // note: exterior models without the RENDER_NOSELFSHADOW
4094 // flag still create a RENDER_NOSELFSHADOW shadow but
4095 // are lit normally, this means that they are
4096 // self-shadowing but do not shadow other
4097 // RENDER_NOSELFSHADOW entities such as the gun
4098 // (very weird, but keeps the player shadow off the gun)
4099 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4100 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4102 shadowentities[numshadowentities++] = ent;
4105 else if (ent->flags & RENDER_SHADOW)
4107 // this entity is not receiving light, but may still need to
4109 // TODO: check if the surfaces in the model can cast shadow
4110 // now check if it is in a leaf seen by the light
4111 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))
4113 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4114 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4115 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4117 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4118 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4120 shadowentities[numshadowentities++] = ent;
4126 // return if there's nothing at all to light
4127 if (!numlightentities && !numsurfaces)
4130 // don't let sound skip if going slow
4131 if (r_refdef.scene.extraupdate)
4134 // make this the active rtlight for rendering purposes
4135 R_Shadow_RenderMode_ActiveLight(rtlight);
4136 // count this light in the r_speeds
4137 r_refdef.stats.lights++;
4139 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4141 // optionally draw visible shape of the shadow volumes
4142 // for performance analysis by level designers
4143 R_Shadow_RenderMode_VisibleShadowVolumes();
4145 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4146 for (i = 0;i < numshadowentities;i++)
4147 R_Shadow_DrawEntityShadow(shadowentities[i]);
4148 for (i = 0;i < numshadowentities_noselfshadow;i++)
4149 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4152 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4154 // optionally draw the illuminated areas
4155 // for performance analysis by level designers
4156 R_Shadow_RenderMode_VisibleLighting(false, false);
4158 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4159 for (i = 0;i < numlightentities;i++)
4160 R_Shadow_DrawEntityLight(lightentities[i]);
4161 for (i = 0;i < numlightentities_noselfshadow;i++)
4162 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4165 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4167 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4168 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4169 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4170 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4172 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4173 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4174 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4176 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4182 int receivermask = 0;
4183 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4184 Matrix4x4_Abs(&radiustolight);
4186 r_shadow_shadowmaplod = 0;
4187 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4188 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4189 r_shadow_shadowmaplod = i;
4191 size = r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE ? r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod : lodlinear;
4192 size = bound(1, size, r_shadow_shadowmapmaxsize);
4193 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4197 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4199 castermask = rtlight->static_shadowmap_casters;
4200 receivermask = rtlight->static_shadowmap_receivers;
4204 for(i = 0;i < numsurfaces;i++)
4206 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4207 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4208 castermask |= surfacesides[i];
4209 receivermask |= surfacesides[i];
4213 if (receivermask < 0x3F)
4215 for (i = 0;i < numlightentities;i++)
4216 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4217 if (receivermask < 0x3F)
4218 for(i = 0; i < numlightentities_noselfshadow;i++)
4219 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4222 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4226 for (i = 0;i < numshadowentities;i++)
4227 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4228 for (i = 0;i < numshadowentities_noselfshadow;i++)
4229 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4232 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4234 // render shadow casters into 6 sided depth texture
4235 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4237 R_Shadow_RenderMode_ShadowMap(side, true, size);
4238 if (! (castermask & (1 << side))) continue;
4240 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4241 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4242 R_Shadow_DrawEntityShadow(shadowentities[i]);
4245 if (numlightentities_noselfshadow)
4247 // render lighting using the depth texture as shadowmap
4248 // draw lighting in the unmasked areas
4249 R_Shadow_RenderMode_Lighting(false, false, true);
4250 for (i = 0;i < numlightentities_noselfshadow;i++)
4251 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4254 // render shadow casters into 6 sided depth texture
4255 if (numshadowentities_noselfshadow)
4257 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4259 R_Shadow_RenderMode_ShadowMap(side, false, size);
4260 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4261 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4265 // render lighting using the depth texture as shadowmap
4266 // draw lighting in the unmasked areas
4267 R_Shadow_RenderMode_Lighting(false, false, true);
4268 // draw lighting in the unmasked areas
4270 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4271 for (i = 0;i < numlightentities;i++)
4272 R_Shadow_DrawEntityLight(lightentities[i]);
4274 else if (castshadows && gl_stencil)
4276 // draw stencil shadow volumes to mask off pixels that are in shadow
4277 // so that they won't receive lighting
4278 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4279 R_Shadow_ClearStencil();
4281 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4282 for (i = 0;i < numshadowentities;i++)
4283 R_Shadow_DrawEntityShadow(shadowentities[i]);
4284 if (numlightentities_noselfshadow)
4286 // draw lighting in the unmasked areas
4287 R_Shadow_RenderMode_Lighting(true, false, false);
4288 for (i = 0;i < numlightentities_noselfshadow;i++)
4289 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4291 // optionally draw the illuminated areas
4292 // for performance analysis by level designers
4293 if (r_showlighting.integer && r_refdef.view.showdebug)
4295 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4296 for (i = 0;i < numlightentities_noselfshadow;i++)
4297 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4300 for (i = 0;i < numshadowentities_noselfshadow;i++)
4301 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4303 if (numsurfaces + numlightentities)
4305 // draw lighting in the unmasked areas
4306 R_Shadow_RenderMode_Lighting(true, false, false);
4308 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4309 for (i = 0;i < numlightentities;i++)
4310 R_Shadow_DrawEntityLight(lightentities[i]);
4315 if (numsurfaces + numlightentities)
4317 // draw lighting in the unmasked areas
4318 R_Shadow_RenderMode_Lighting(false, false, false);
4320 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4321 for (i = 0;i < numlightentities;i++)
4322 R_Shadow_DrawEntityLight(lightentities[i]);
4323 for (i = 0;i < numlightentities_noselfshadow;i++)
4324 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4329 void R_Shadow_DrawLightSprites(void);
4330 void R_ShadowVolumeLighting(qboolean visible)
4338 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4) ||
4339 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) ||
4340 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4341 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4342 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4343 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4344 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4345 R_Shadow_FreeShadowMaps();
4347 if (r_editlights.integer)
4348 R_Shadow_DrawLightSprites();
4350 R_Shadow_RenderMode_Begin();
4352 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4353 if (r_shadow_debuglight.integer >= 0)
4355 lightindex = r_shadow_debuglight.integer;
4356 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4357 if (light && (light->flags & flag))
4358 R_DrawRTLight(&light->rtlight, visible);
4362 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4363 for (lightindex = 0;lightindex < range;lightindex++)
4365 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4366 if (light && (light->flags & flag))
4367 R_DrawRTLight(&light->rtlight, visible);
4370 if (r_refdef.scene.rtdlight)
4371 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4372 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4374 R_Shadow_RenderMode_End();
4377 extern const float r_screenvertex3f[12];
4378 extern void R_SetupView(qboolean allowwaterclippingplane);
4379 extern void R_ResetViewRendering3D(void);
4380 extern void R_ResetViewRendering2D(void);
4381 extern cvar_t r_shadows;
4382 extern cvar_t r_shadows_darken;
4383 extern cvar_t r_shadows_drawafterrtlighting;
4384 extern cvar_t r_shadows_castfrombmodels;
4385 extern cvar_t r_shadows_throwdistance;
4386 extern cvar_t r_shadows_throwdirection;
4387 void R_DrawModelShadows(void)
4390 float relativethrowdistance;
4391 entity_render_t *ent;
4392 vec3_t relativelightorigin;
4393 vec3_t relativelightdirection;
4394 vec3_t relativeshadowmins, relativeshadowmaxs;
4395 vec3_t tmp, shadowdir;
4397 if (!r_drawentities.integer || !gl_stencil)
4401 R_ResetViewRendering3D();
4402 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4403 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4404 R_Shadow_RenderMode_Begin();
4405 R_Shadow_RenderMode_ActiveLight(NULL);
4406 r_shadow_lightscissor[0] = r_refdef.view.x;
4407 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4408 r_shadow_lightscissor[2] = r_refdef.view.width;
4409 r_shadow_lightscissor[3] = r_refdef.view.height;
4410 R_Shadow_RenderMode_StencilShadowVolumes(false);
4413 if (r_shadows.integer == 2)
4415 Math_atov(r_shadows_throwdirection.string, shadowdir);
4416 VectorNormalize(shadowdir);
4419 R_Shadow_ClearStencil();
4421 for (i = 0;i < r_refdef.scene.numentities;i++)
4423 ent = r_refdef.scene.entities[i];
4425 // cast shadows from anything of the map (submodels are optional)
4426 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4428 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4429 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4430 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4431 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4432 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4435 if(ent->entitynumber != 0)
4437 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4438 int entnum, entnum2, recursion;
4439 entnum = entnum2 = ent->entitynumber;
4440 for(recursion = 32; recursion > 0; --recursion)
4442 entnum2 = cl.entities[entnum].state_current.tagentity;
4443 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4448 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4450 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4451 // transform into modelspace of OUR entity
4452 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4453 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4456 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4459 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4462 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4463 RSurf_ActiveModelEntity(ent, false, false);
4464 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4465 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4469 // not really the right mode, but this will disable any silly stencil features
4470 R_Shadow_RenderMode_End();
4472 // set up ortho view for rendering this pass
4473 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4474 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4475 //GL_ScissorTest(true);
4476 //R_Mesh_Matrix(&identitymatrix);
4477 //R_Mesh_ResetTextureState();
4478 R_ResetViewRendering2D();
4479 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4480 R_Mesh_ColorPointer(NULL, 0, 0);
4481 R_SetupGenericShader(false);
4483 // set up a darkening blend on shadowed areas
4484 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4485 //GL_DepthRange(0, 1);
4486 //GL_DepthTest(false);
4487 //GL_DepthMask(false);
4488 //GL_PolygonOffset(0, 0);CHECKGLERROR
4489 GL_Color(0, 0, 0, r_shadows_darken.value);
4490 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4491 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4492 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4493 qglStencilMask(~0);CHECKGLERROR
4494 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4495 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4497 // apply the blend to the shadowed areas
4498 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4500 // restore the viewport
4501 R_SetViewport(&r_refdef.view.viewport);
4503 // restore other state to normal
4504 //R_Shadow_RenderMode_End();
4507 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4510 vec3_t centerorigin;
4511 // if it's too close, skip it
4512 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4514 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4517 if (usequery && r_numqueries + 2 <= r_maxqueries)
4519 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4520 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4521 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4524 // 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
4525 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4526 qglDepthFunc(GL_ALWAYS);
4527 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);
4528 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4529 qglDepthFunc(GL_LEQUAL);
4530 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4531 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);
4532 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4535 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4538 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4541 GLint allpixels = 0, visiblepixels = 0;
4542 // now we have to check the query result
4543 if (rtlight->corona_queryindex_visiblepixels)
4546 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4547 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4549 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4550 if (visiblepixels < 1 || allpixels < 1)
4552 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4553 cscale *= rtlight->corona_visibility;
4557 // FIXME: these traces should scan all render entities instead of cl.world
4558 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4561 VectorScale(rtlight->color, cscale, color);
4562 if (VectorLength(color) > (1.0f / 256.0f))
4563 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);
4566 void R_DrawCoronas(void)
4574 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4576 if (r_waterstate.renderingscene)
4578 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4579 R_Mesh_Matrix(&identitymatrix);
4581 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4583 // check occlusion of coronas
4584 // use GL_ARB_occlusion_query if available
4585 // otherwise use raytraces
4587 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4590 GL_ColorMask(0,0,0,0);
4591 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4592 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4595 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4596 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4598 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4602 for (lightindex = 0;lightindex < range;lightindex++)
4604 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4607 rtlight = &light->rtlight;
4608 rtlight->corona_visibility = 0;
4609 rtlight->corona_queryindex_visiblepixels = 0;
4610 rtlight->corona_queryindex_allpixels = 0;
4611 if (!(rtlight->flags & flag))
4613 if (rtlight->corona <= 0)
4615 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4617 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4619 for (i = 0;i < r_refdef.scene.numlights;i++)
4621 rtlight = r_refdef.scene.lights[i];
4622 rtlight->corona_visibility = 0;
4623 rtlight->corona_queryindex_visiblepixels = 0;
4624 rtlight->corona_queryindex_allpixels = 0;
4625 if (!(rtlight->flags & flag))
4627 if (rtlight->corona <= 0)
4629 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4632 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4634 // now draw the coronas using the query data for intensity info
4635 for (lightindex = 0;lightindex < range;lightindex++)
4637 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4640 rtlight = &light->rtlight;
4641 if (rtlight->corona_visibility <= 0)
4643 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4645 for (i = 0;i < r_refdef.scene.numlights;i++)
4647 rtlight = r_refdef.scene.lights[i];
4648 if (rtlight->corona_visibility <= 0)
4650 if (gl_flashblend.integer)
4651 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4653 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4659 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4660 typedef struct suffixinfo_s
4663 qboolean flipx, flipy, flipdiagonal;
4666 static suffixinfo_t suffix[3][6] =
4669 {"px", false, false, false},
4670 {"nx", false, false, false},
4671 {"py", false, false, false},
4672 {"ny", false, false, false},
4673 {"pz", false, false, false},
4674 {"nz", false, false, false}
4677 {"posx", false, false, false},
4678 {"negx", false, false, false},
4679 {"posy", false, false, false},
4680 {"negy", false, false, false},
4681 {"posz", false, false, false},
4682 {"negz", false, false, false}
4685 {"rt", true, false, true},
4686 {"lf", false, true, true},
4687 {"ft", true, true, false},
4688 {"bk", false, false, false},
4689 {"up", true, false, true},
4690 {"dn", true, false, true}
4694 static int componentorder[4] = {0, 1, 2, 3};
4696 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4698 int i, j, cubemapsize;
4699 unsigned char *cubemappixels, *image_buffer;
4700 rtexture_t *cubemaptexture;
4702 // must start 0 so the first loadimagepixels has no requested width/height
4704 cubemappixels = NULL;
4705 cubemaptexture = NULL;
4706 // keep trying different suffix groups (posx, px, rt) until one loads
4707 for (j = 0;j < 3 && !cubemappixels;j++)
4709 // load the 6 images in the suffix group
4710 for (i = 0;i < 6;i++)
4712 // generate an image name based on the base and and suffix
4713 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4715 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4717 // an image loaded, make sure width and height are equal
4718 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4720 // if this is the first image to load successfully, allocate the cubemap memory
4721 if (!cubemappixels && image_width >= 1)
4723 cubemapsize = image_width;
4724 // note this clears to black, so unavailable sides are black
4725 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4727 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4729 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);
4732 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4734 Mem_Free(image_buffer);
4738 // if a cubemap loaded, upload it
4741 if (developer_loading.integer)
4742 Con_Printf("loading cubemap \"%s\"\n", basename);
4744 if (!r_shadow_filters_texturepool)
4745 r_shadow_filters_texturepool = R_AllocTexturePool();
4746 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4747 Mem_Free(cubemappixels);
4751 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4752 if (developer_loading.integer)
4754 Con_Printf("(tried tried images ");
4755 for (j = 0;j < 3;j++)
4756 for (i = 0;i < 6;i++)
4757 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4758 Con_Print(" and was unable to find any of them).\n");
4761 return cubemaptexture;
4764 rtexture_t *R_Shadow_Cubemap(const char *basename)
4767 for (i = 0;i < numcubemaps;i++)
4768 if (!strcasecmp(cubemaps[i].basename, basename))
4769 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4770 if (i >= MAX_CUBEMAPS)
4771 return r_texture_whitecube;
4773 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4774 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4775 return cubemaps[i].texture;
4778 void R_Shadow_FreeCubemaps(void)
4781 for (i = 0;i < numcubemaps;i++)
4783 if (developer_loading.integer)
4784 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4785 if (cubemaps[i].texture)
4786 R_FreeTexture(cubemaps[i].texture);
4790 R_FreeTexturePool(&r_shadow_filters_texturepool);
4793 dlight_t *R_Shadow_NewWorldLight(void)
4795 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4798 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)
4801 // validate parameters
4802 if (style < 0 || style >= MAX_LIGHTSTYLES)
4804 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4810 // copy to light properties
4811 VectorCopy(origin, light->origin);
4812 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4813 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4814 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4815 light->color[0] = max(color[0], 0);
4816 light->color[1] = max(color[1], 0);
4817 light->color[2] = max(color[2], 0);
4818 light->radius = max(radius, 0);
4819 light->style = style;
4820 light->shadow = shadowenable;
4821 light->corona = corona;
4822 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4823 light->coronasizescale = coronasizescale;
4824 light->ambientscale = ambientscale;
4825 light->diffusescale = diffusescale;
4826 light->specularscale = specularscale;
4827 light->flags = flags;
4829 // update renderable light data
4830 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4831 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);
4834 void R_Shadow_FreeWorldLight(dlight_t *light)
4836 if (r_shadow_selectedlight == light)
4837 r_shadow_selectedlight = NULL;
4838 R_RTLight_Uncompile(&light->rtlight);
4839 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4842 void R_Shadow_ClearWorldLights(void)
4846 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4847 for (lightindex = 0;lightindex < range;lightindex++)
4849 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4851 R_Shadow_FreeWorldLight(light);
4853 r_shadow_selectedlight = NULL;
4854 R_Shadow_FreeCubemaps();
4857 void R_Shadow_SelectLight(dlight_t *light)
4859 if (r_shadow_selectedlight)
4860 r_shadow_selectedlight->selected = false;
4861 r_shadow_selectedlight = light;
4862 if (r_shadow_selectedlight)
4863 r_shadow_selectedlight->selected = true;
4866 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4868 // this is never batched (there can be only one)
4869 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);
4872 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4879 // this is never batched (due to the ent parameter changing every time)
4880 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4881 const dlight_t *light = (dlight_t *)ent;
4884 VectorScale(light->color, intensity, spritecolor);
4885 if (VectorLength(spritecolor) < 0.1732f)
4886 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4887 if (VectorLength(spritecolor) > 1.0f)
4888 VectorNormalize(spritecolor);
4890 // draw light sprite
4891 if (light->cubemapname[0] && !light->shadow)
4892 pic = r_editlights_sprcubemapnoshadowlight;
4893 else if (light->cubemapname[0])
4894 pic = r_editlights_sprcubemaplight;
4895 else if (!light->shadow)
4896 pic = r_editlights_sprnoshadowlight;
4898 pic = r_editlights_sprlight;
4899 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);
4900 // draw selection sprite if light is selected
4901 if (light->selected)
4902 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);
4903 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4906 void R_Shadow_DrawLightSprites(void)
4910 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4911 for (lightindex = 0;lightindex < range;lightindex++)
4913 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4915 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4917 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4920 void R_Shadow_SelectLightInView(void)
4922 float bestrating, rating, temp[3];
4926 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4929 for (lightindex = 0;lightindex < range;lightindex++)
4931 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4934 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4935 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4938 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4939 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4941 bestrating = rating;
4946 R_Shadow_SelectLight(best);
4949 void R_Shadow_LoadWorldLights(void)
4951 int n, a, style, shadow, flags;
4952 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4953 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4954 if (cl.worldmodel == NULL)
4956 Con_Print("No map loaded.\n");
4959 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4960 strlcat (name, ".rtlights", sizeof (name));
4961 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4971 for (;COM_Parse(t, true) && strcmp(
4972 if (COM_Parse(t, true))
4974 if (com_token[0] == '!')
4977 origin[0] = atof(com_token+1);
4980 origin[0] = atof(com_token);
4985 while (*s && *s != '\n' && *s != '\r')
4991 // check for modifier flags
4998 #if _MSC_VER >= 1400
4999 #define sscanf sscanf_s
5001 cubemapname[sizeof(cubemapname)-1] = 0;
5002 #if MAX_QPATH != 128
5003 #error update this code if MAX_QPATH changes
5005 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
5006 #if _MSC_VER >= 1400
5007 , sizeof(cubemapname)
5009 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5012 flags = LIGHTFLAG_REALTIMEMODE;
5020 coronasizescale = 0.25f;
5022 VectorClear(angles);
5025 if (a < 9 || !strcmp(cubemapname, "\"\""))
5027 // remove quotes on cubemapname
5028 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5031 namelen = strlen(cubemapname) - 2;
5032 memmove(cubemapname, cubemapname + 1, namelen);
5033 cubemapname[namelen] = '\0';
5037 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);
5040 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5048 Con_Printf("invalid rtlights file \"%s\"\n", name);
5049 Mem_Free(lightsstring);
5053 void R_Shadow_SaveWorldLights(void)
5057 size_t bufchars, bufmaxchars;
5059 char name[MAX_QPATH];
5060 char line[MAX_INPUTLINE];
5061 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5062 // I hate lines which are 3 times my screen size :( --blub
5065 if (cl.worldmodel == NULL)
5067 Con_Print("No map loaded.\n");
5070 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5071 strlcat (name, ".rtlights", sizeof (name));
5072 bufchars = bufmaxchars = 0;
5074 for (lightindex = 0;lightindex < range;lightindex++)
5076 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5079 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5080 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);
5081 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5082 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]);
5084 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);
5085 if (bufchars + strlen(line) > bufmaxchars)
5087 bufmaxchars = bufchars + strlen(line) + 2048;
5089 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5093 memcpy(buf, oldbuf, bufchars);
5099 memcpy(buf + bufchars, line, strlen(line));
5100 bufchars += strlen(line);
5104 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5109 void R_Shadow_LoadLightsFile(void)
5112 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5113 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5114 if (cl.worldmodel == NULL)
5116 Con_Print("No map loaded.\n");
5119 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5120 strlcat (name, ".lights", sizeof (name));
5121 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5129 while (*s && *s != '\n' && *s != '\r')
5135 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);
5139 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);
5142 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5143 radius = bound(15, radius, 4096);
5144 VectorScale(color, (2.0f / (8388608.0f)), color);
5145 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5153 Con_Printf("invalid lights file \"%s\"\n", name);
5154 Mem_Free(lightsstring);
5158 // tyrlite/hmap2 light types in the delay field
5159 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5161 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5163 int entnum, style, islight, skin, pflags, effects, type, n;
5166 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5167 char key[256], value[MAX_INPUTLINE];
5169 if (cl.worldmodel == NULL)
5171 Con_Print("No map loaded.\n");
5174 // try to load a .ent file first
5175 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5176 strlcat (key, ".ent", sizeof (key));
5177 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5178 // and if that is not found, fall back to the bsp file entity string
5180 data = cl.worldmodel->brush.entities;
5183 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5185 type = LIGHTTYPE_MINUSX;
5186 origin[0] = origin[1] = origin[2] = 0;
5187 originhack[0] = originhack[1] = originhack[2] = 0;
5188 angles[0] = angles[1] = angles[2] = 0;
5189 color[0] = color[1] = color[2] = 1;
5190 light[0] = light[1] = light[2] = 1;light[3] = 300;
5191 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5201 if (!COM_ParseToken_Simple(&data, false, false))
5203 if (com_token[0] == '}')
5204 break; // end of entity
5205 if (com_token[0] == '_')
5206 strlcpy(key, com_token + 1, sizeof(key));
5208 strlcpy(key, com_token, sizeof(key));
5209 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5210 key[strlen(key)-1] = 0;
5211 if (!COM_ParseToken_Simple(&data, false, false))
5213 strlcpy(value, com_token, sizeof(value));
5215 // now that we have the key pair worked out...
5216 if (!strcmp("light", key))
5218 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5222 light[0] = vec[0] * (1.0f / 256.0f);
5223 light[1] = vec[0] * (1.0f / 256.0f);
5224 light[2] = vec[0] * (1.0f / 256.0f);
5230 light[0] = vec[0] * (1.0f / 255.0f);
5231 light[1] = vec[1] * (1.0f / 255.0f);
5232 light[2] = vec[2] * (1.0f / 255.0f);
5236 else if (!strcmp("delay", key))
5238 else if (!strcmp("origin", key))
5239 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5240 else if (!strcmp("angle", key))
5241 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5242 else if (!strcmp("angles", key))
5243 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5244 else if (!strcmp("color", key))
5245 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5246 else if (!strcmp("wait", key))
5247 fadescale = atof(value);
5248 else if (!strcmp("classname", key))
5250 if (!strncmp(value, "light", 5))
5253 if (!strcmp(value, "light_fluoro"))
5258 overridecolor[0] = 1;
5259 overridecolor[1] = 1;
5260 overridecolor[2] = 1;
5262 if (!strcmp(value, "light_fluorospark"))
5267 overridecolor[0] = 1;
5268 overridecolor[1] = 1;
5269 overridecolor[2] = 1;
5271 if (!strcmp(value, "light_globe"))
5276 overridecolor[0] = 1;
5277 overridecolor[1] = 0.8;
5278 overridecolor[2] = 0.4;
5280 if (!strcmp(value, "light_flame_large_yellow"))
5285 overridecolor[0] = 1;
5286 overridecolor[1] = 0.5;
5287 overridecolor[2] = 0.1;
5289 if (!strcmp(value, "light_flame_small_yellow"))
5294 overridecolor[0] = 1;
5295 overridecolor[1] = 0.5;
5296 overridecolor[2] = 0.1;
5298 if (!strcmp(value, "light_torch_small_white"))
5303 overridecolor[0] = 1;
5304 overridecolor[1] = 0.5;
5305 overridecolor[2] = 0.1;
5307 if (!strcmp(value, "light_torch_small_walltorch"))
5312 overridecolor[0] = 1;
5313 overridecolor[1] = 0.5;
5314 overridecolor[2] = 0.1;
5318 else if (!strcmp("style", key))
5319 style = atoi(value);
5320 else if (!strcmp("skin", key))
5321 skin = (int)atof(value);
5322 else if (!strcmp("pflags", key))
5323 pflags = (int)atof(value);
5324 else if (!strcmp("effects", key))
5325 effects = (int)atof(value);
5326 else if (cl.worldmodel->type == mod_brushq3)
5328 if (!strcmp("scale", key))
5329 lightscale = atof(value);
5330 if (!strcmp("fade", key))
5331 fadescale = atof(value);
5336 if (lightscale <= 0)
5340 if (color[0] == color[1] && color[0] == color[2])
5342 color[0] *= overridecolor[0];
5343 color[1] *= overridecolor[1];
5344 color[2] *= overridecolor[2];
5346 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5347 color[0] = color[0] * light[0];
5348 color[1] = color[1] * light[1];
5349 color[2] = color[2] * light[2];
5352 case LIGHTTYPE_MINUSX:
5354 case LIGHTTYPE_RECIPX:
5356 VectorScale(color, (1.0f / 16.0f), color);
5358 case LIGHTTYPE_RECIPXX:
5360 VectorScale(color, (1.0f / 16.0f), color);
5363 case LIGHTTYPE_NONE:
5367 case LIGHTTYPE_MINUSXX:
5370 VectorAdd(origin, originhack, origin);
5372 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);
5375 Mem_Free(entfiledata);
5379 void R_Shadow_SetCursorLocationForView(void)
5382 vec3_t dest, endpos;
5384 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5385 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5386 if (trace.fraction < 1)
5388 dist = trace.fraction * r_editlights_cursordistance.value;
5389 push = r_editlights_cursorpushback.value;
5393 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5394 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5398 VectorClear( endpos );
5400 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5401 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5402 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5405 void R_Shadow_UpdateWorldLightSelection(void)
5407 if (r_editlights.integer)
5409 R_Shadow_SetCursorLocationForView();
5410 R_Shadow_SelectLightInView();
5413 R_Shadow_SelectLight(NULL);
5416 void R_Shadow_EditLights_Clear_f(void)
5418 R_Shadow_ClearWorldLights();
5421 void R_Shadow_EditLights_Reload_f(void)
5425 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5426 R_Shadow_ClearWorldLights();
5427 R_Shadow_LoadWorldLights();
5428 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5430 R_Shadow_LoadLightsFile();
5431 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5432 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5436 void R_Shadow_EditLights_Save_f(void)
5440 R_Shadow_SaveWorldLights();
5443 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5445 R_Shadow_ClearWorldLights();
5446 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5449 void R_Shadow_EditLights_ImportLightsFile_f(void)
5451 R_Shadow_ClearWorldLights();
5452 R_Shadow_LoadLightsFile();
5455 void R_Shadow_EditLights_Spawn_f(void)
5458 if (!r_editlights.integer)
5460 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5463 if (Cmd_Argc() != 1)
5465 Con_Print("r_editlights_spawn does not take parameters\n");
5468 color[0] = color[1] = color[2] = 1;
5469 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5472 void R_Shadow_EditLights_Edit_f(void)
5474 vec3_t origin, angles, color;
5475 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5476 int style, shadows, flags, normalmode, realtimemode;
5477 char cubemapname[MAX_INPUTLINE];
5478 if (!r_editlights.integer)
5480 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5483 if (!r_shadow_selectedlight)
5485 Con_Print("No selected light.\n");
5488 VectorCopy(r_shadow_selectedlight->origin, origin);
5489 VectorCopy(r_shadow_selectedlight->angles, angles);
5490 VectorCopy(r_shadow_selectedlight->color, color);
5491 radius = r_shadow_selectedlight->radius;
5492 style = r_shadow_selectedlight->style;
5493 if (r_shadow_selectedlight->cubemapname)
5494 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5497 shadows = r_shadow_selectedlight->shadow;
5498 corona = r_shadow_selectedlight->corona;
5499 coronasizescale = r_shadow_selectedlight->coronasizescale;
5500 ambientscale = r_shadow_selectedlight->ambientscale;
5501 diffusescale = r_shadow_selectedlight->diffusescale;
5502 specularscale = r_shadow_selectedlight->specularscale;
5503 flags = r_shadow_selectedlight->flags;
5504 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5505 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5506 if (!strcmp(Cmd_Argv(1), "origin"))
5508 if (Cmd_Argc() != 5)
5510 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5513 origin[0] = atof(Cmd_Argv(2));
5514 origin[1] = atof(Cmd_Argv(3));
5515 origin[2] = atof(Cmd_Argv(4));
5517 else if (!strcmp(Cmd_Argv(1), "originx"))
5519 if (Cmd_Argc() != 3)
5521 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5524 origin[0] = atof(Cmd_Argv(2));
5526 else if (!strcmp(Cmd_Argv(1), "originy"))
5528 if (Cmd_Argc() != 3)
5530 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5533 origin[1] = atof(Cmd_Argv(2));
5535 else if (!strcmp(Cmd_Argv(1), "originz"))
5537 if (Cmd_Argc() != 3)
5539 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5542 origin[2] = atof(Cmd_Argv(2));
5544 else if (!strcmp(Cmd_Argv(1), "move"))
5546 if (Cmd_Argc() != 5)
5548 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5551 origin[0] += atof(Cmd_Argv(2));
5552 origin[1] += atof(Cmd_Argv(3));
5553 origin[2] += atof(Cmd_Argv(4));
5555 else if (!strcmp(Cmd_Argv(1), "movex"))
5557 if (Cmd_Argc() != 3)
5559 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5562 origin[0] += atof(Cmd_Argv(2));
5564 else if (!strcmp(Cmd_Argv(1), "movey"))
5566 if (Cmd_Argc() != 3)
5568 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5571 origin[1] += atof(Cmd_Argv(2));
5573 else if (!strcmp(Cmd_Argv(1), "movez"))
5575 if (Cmd_Argc() != 3)
5577 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5580 origin[2] += atof(Cmd_Argv(2));
5582 else if (!strcmp(Cmd_Argv(1), "angles"))
5584 if (Cmd_Argc() != 5)
5586 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5589 angles[0] = atof(Cmd_Argv(2));
5590 angles[1] = atof(Cmd_Argv(3));
5591 angles[2] = atof(Cmd_Argv(4));
5593 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5595 if (Cmd_Argc() != 3)
5597 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5600 angles[0] = atof(Cmd_Argv(2));
5602 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5604 if (Cmd_Argc() != 3)
5606 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5609 angles[1] = atof(Cmd_Argv(2));
5611 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5613 if (Cmd_Argc() != 3)
5615 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5618 angles[2] = atof(Cmd_Argv(2));
5620 else if (!strcmp(Cmd_Argv(1), "color"))
5622 if (Cmd_Argc() != 5)
5624 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5627 color[0] = atof(Cmd_Argv(2));
5628 color[1] = atof(Cmd_Argv(3));
5629 color[2] = atof(Cmd_Argv(4));
5631 else if (!strcmp(Cmd_Argv(1), "radius"))
5633 if (Cmd_Argc() != 3)
5635 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5638 radius = atof(Cmd_Argv(2));
5640 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5642 if (Cmd_Argc() == 3)
5644 double scale = atof(Cmd_Argv(2));
5651 if (Cmd_Argc() != 5)
5653 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5656 color[0] *= atof(Cmd_Argv(2));
5657 color[1] *= atof(Cmd_Argv(3));
5658 color[2] *= atof(Cmd_Argv(4));
5661 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5663 if (Cmd_Argc() != 3)
5665 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5668 radius *= atof(Cmd_Argv(2));
5670 else if (!strcmp(Cmd_Argv(1), "style"))
5672 if (Cmd_Argc() != 3)
5674 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5677 style = atoi(Cmd_Argv(2));
5679 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5683 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5686 if (Cmd_Argc() == 3)
5687 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5691 else if (!strcmp(Cmd_Argv(1), "shadows"))
5693 if (Cmd_Argc() != 3)
5695 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5698 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5700 else if (!strcmp(Cmd_Argv(1), "corona"))
5702 if (Cmd_Argc() != 3)
5704 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5707 corona = atof(Cmd_Argv(2));
5709 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5711 if (Cmd_Argc() != 3)
5713 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5716 coronasizescale = atof(Cmd_Argv(2));
5718 else if (!strcmp(Cmd_Argv(1), "ambient"))
5720 if (Cmd_Argc() != 3)
5722 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5725 ambientscale = atof(Cmd_Argv(2));
5727 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5729 if (Cmd_Argc() != 3)
5731 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5734 diffusescale = atof(Cmd_Argv(2));
5736 else if (!strcmp(Cmd_Argv(1), "specular"))
5738 if (Cmd_Argc() != 3)
5740 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5743 specularscale = atof(Cmd_Argv(2));
5745 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5747 if (Cmd_Argc() != 3)
5749 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5752 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5754 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5756 if (Cmd_Argc() != 3)
5758 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5761 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5765 Con_Print("usage: r_editlights_edit [property] [value]\n");
5766 Con_Print("Selected light's properties:\n");
5767 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5768 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5769 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5770 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5771 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5772 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5773 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5774 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5775 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5776 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5777 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5778 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5779 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5780 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5783 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5784 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5787 void R_Shadow_EditLights_EditAll_f(void)
5793 if (!r_editlights.integer)
5795 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5799 // EditLights doesn't seem to have a "remove" command or something so:
5800 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5801 for (lightindex = 0;lightindex < range;lightindex++)
5803 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5806 R_Shadow_SelectLight(light);
5807 R_Shadow_EditLights_Edit_f();
5811 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5813 int lightnumber, lightcount;
5814 size_t lightindex, range;
5818 if (!r_editlights.integer)
5820 x = vid_conwidth.value - 240;
5822 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5825 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5826 for (lightindex = 0;lightindex < range;lightindex++)
5828 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5831 if (light == r_shadow_selectedlight)
5832 lightnumber = lightindex;
5835 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;
5836 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;
5838 if (r_shadow_selectedlight == NULL)
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5845 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;
5846 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;
5847 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;
5848 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;
5849 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;
5850 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;
5851 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;
5852 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;
5853 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;
5854 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;
5857 void R_Shadow_EditLights_ToggleShadow_f(void)
5859 if (!r_editlights.integer)
5861 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5864 if (!r_shadow_selectedlight)
5866 Con_Print("No selected light.\n");
5869 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);
5872 void R_Shadow_EditLights_ToggleCorona_f(void)
5874 if (!r_editlights.integer)
5876 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5879 if (!r_shadow_selectedlight)
5881 Con_Print("No selected light.\n");
5884 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);
5887 void R_Shadow_EditLights_Remove_f(void)
5889 if (!r_editlights.integer)
5891 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5894 if (!r_shadow_selectedlight)
5896 Con_Print("No selected light.\n");
5899 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5900 r_shadow_selectedlight = NULL;
5903 void R_Shadow_EditLights_Help_f(void)
5906 "Documentation on r_editlights system:\n"
5908 "r_editlights : enable/disable editing mode\n"
5909 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5910 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5911 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5912 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5913 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5915 "r_editlights_help : this help\n"
5916 "r_editlights_clear : remove all lights\n"
5917 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5918 "r_editlights_save : save to .rtlights file\n"
5919 "r_editlights_spawn : create a light with default settings\n"
5920 "r_editlights_edit command : edit selected light - more documentation below\n"
5921 "r_editlights_remove : remove selected light\n"
5922 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5923 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5924 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5926 "origin x y z : set light location\n"
5927 "originx x: set x component of light location\n"
5928 "originy y: set y component of light location\n"
5929 "originz z: set z component of light location\n"
5930 "move x y z : adjust light location\n"
5931 "movex x: adjust x component of light location\n"
5932 "movey y: adjust y component of light location\n"
5933 "movez z: adjust z component of light location\n"
5934 "angles x y z : set light angles\n"
5935 "anglesx x: set x component of light angles\n"
5936 "anglesy y: set y component of light angles\n"
5937 "anglesz z: set z component of light angles\n"
5938 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5939 "radius radius : set radius (size) of light\n"
5940 "colorscale grey : multiply color of light (1 does nothing)\n"
5941 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5942 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5943 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5944 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5945 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5946 "shadows 1/0 : turn on/off shadows\n"
5947 "corona n : set corona intensity\n"
5948 "coronasize n : set corona size (0-1)\n"
5949 "ambient n : set ambient intensity (0-1)\n"
5950 "diffuse n : set diffuse intensity (0-1)\n"
5951 "specular n : set specular intensity (0-1)\n"
5952 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5953 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5954 "<nothing> : print light properties to console\n"
5958 void R_Shadow_EditLights_CopyInfo_f(void)
5960 if (!r_editlights.integer)
5962 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5965 if (!r_shadow_selectedlight)
5967 Con_Print("No selected light.\n");
5970 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5971 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5972 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5973 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5974 if (r_shadow_selectedlight->cubemapname)
5975 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5977 r_shadow_bufferlight.cubemapname[0] = 0;
5978 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5979 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5980 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5981 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5982 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5983 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5984 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5987 void R_Shadow_EditLights_PasteInfo_f(void)
5989 if (!r_editlights.integer)
5991 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5994 if (!r_shadow_selectedlight)
5996 Con_Print("No selected light.\n");
5999 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);
6002 void R_Shadow_EditLights_Init(void)
6004 Cvar_RegisterVariable(&r_editlights);
6005 Cvar_RegisterVariable(&r_editlights_cursordistance);
6006 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6007 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6008 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6009 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6010 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6011 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6012 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)");
6013 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6014 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6015 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6016 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)");
6017 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6018 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6019 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6020 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6021 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6022 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6023 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)");
6029 =============================================================================
6033 =============================================================================
6036 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6038 VectorClear(diffusecolor);
6039 VectorClear(diffusenormal);
6041 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6043 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6044 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6047 VectorSet(ambientcolor, 1, 1, 1);
6054 for (i = 0;i < r_refdef.scene.numlights;i++)
6056 light = r_refdef.scene.lights[i];
6057 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6058 f = 1 - VectorLength2(v);
6059 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6060 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);