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_Shadow_FreeShadowMaps();
1698 R_FreeTexturePool(&r_shadow_texturepool);
1699 r_shadow_texturepool = R_AllocTexturePool();
1700 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1701 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1702 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1703 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1704 for (x = 0;x <= ATTENTABLESIZE;x++)
1706 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1707 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1708 r_shadow_attentable[x] = bound(0, intensity, 1);
1710 // 1D gradient texture
1711 for (x = 0;x < ATTEN1DSIZE;x++)
1712 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1713 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);
1714 // 2D circle texture
1715 for (y = 0;y < ATTEN2DSIZE;y++)
1716 for (x = 0;x < ATTEN2DSIZE;x++)
1717 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);
1718 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);
1719 // 3D sphere texture
1720 if (r_shadow_texture3d.integer && gl_texture3d)
1722 for (z = 0;z < ATTEN3DSIZE;z++)
1723 for (y = 0;y < ATTEN3DSIZE;y++)
1724 for (x = 0;x < ATTEN3DSIZE;x++)
1725 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));
1726 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);
1729 r_shadow_attenuation3dtexture = NULL;
1732 R_Shadow_MakeTextures_MakeCorona();
1734 // Editor light sprites
1735 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1736 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1737 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1738 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1739 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1740 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1743 void R_Shadow_ValidateCvars(void)
1745 if (r_shadow_texture3d.integer && !gl_texture3d)
1746 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1747 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1748 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1749 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1750 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1753 void R_Shadow_RenderMode_Begin(void)
1759 R_Shadow_ValidateCvars();
1761 if (!r_shadow_attenuation2dtexture
1762 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1763 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1764 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1765 R_Shadow_MakeTextures();
1768 R_Mesh_ColorPointer(NULL, 0, 0);
1769 R_Mesh_ResetTextureState();
1770 GL_BlendFunc(GL_ONE, GL_ZERO);
1771 GL_DepthRange(0, 1);
1772 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1774 GL_DepthMask(false);
1775 GL_Color(0, 0, 0, 1);
1776 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1778 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1780 if (gl_ext_separatestencil.integer)
1782 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1783 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1785 else if (gl_ext_stenciltwoside.integer)
1787 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1788 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1792 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1793 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1796 if (r_glsl.integer && gl_support_fragment_shader)
1797 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1798 else if (gl_dot3arb && gl_texturecubemap && r_shadow_dot3.integer && gl_stencil)
1799 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1801 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1805 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1806 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1807 r_shadow_drawbuffer = drawbuffer;
1808 r_shadow_readbuffer = readbuffer;
1810 r_shadow_cullface_front = r_refdef.view.cullface_front;
1811 r_shadow_cullface_back = r_refdef.view.cullface_back;
1814 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1816 rsurface.rtlight = rtlight;
1819 void R_Shadow_RenderMode_Reset(void)
1822 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1824 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1826 if (gl_support_ext_framebuffer_object)
1828 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1831 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1832 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1834 R_SetViewport(&r_refdef.view.viewport);
1835 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1836 R_Mesh_ColorPointer(NULL, 0, 0);
1837 R_Mesh_ResetTextureState();
1838 GL_DepthRange(0, 1);
1840 GL_DepthMask(false);
1841 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1842 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1843 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1844 qglStencilMask(~0);CHECKGLERROR
1845 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1846 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1847 r_refdef.view.cullface_front = r_shadow_cullface_front;
1848 r_refdef.view.cullface_back = r_shadow_cullface_back;
1849 GL_CullFace(r_refdef.view.cullface_back);
1850 GL_Color(1, 1, 1, 1);
1851 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1852 GL_BlendFunc(GL_ONE, GL_ZERO);
1853 R_SetupGenericShader(false);
1854 r_shadow_usingshadowmaprect = false;
1855 r_shadow_usingshadowmapcube = false;
1856 r_shadow_usingshadowmap2d = false;
1860 void R_Shadow_ClearStencil(void)
1863 GL_Clear(GL_STENCIL_BUFFER_BIT);
1864 r_refdef.stats.lights_clears++;
1867 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1869 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1870 if (r_shadow_rendermode == mode)
1873 R_Shadow_RenderMode_Reset();
1874 GL_ColorMask(0, 0, 0, 0);
1875 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1876 R_SetupDepthOrShadowShader();
1877 qglDepthFunc(GL_LESS);CHECKGLERROR
1878 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1879 r_shadow_rendermode = mode;
1884 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1885 GL_CullFace(GL_NONE);
1886 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1887 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1889 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1890 GL_CullFace(GL_NONE);
1891 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1892 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1894 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1895 GL_CullFace(GL_NONE);
1896 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1897 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1898 qglStencilMask(~0);CHECKGLERROR
1899 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1900 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1901 qglStencilMask(~0);CHECKGLERROR
1902 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1904 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1905 GL_CullFace(GL_NONE);
1906 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1907 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1908 qglStencilMask(~0);CHECKGLERROR
1909 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1910 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1911 qglStencilMask(~0);CHECKGLERROR
1912 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1917 static void R_Shadow_MakeVSDCT(void)
1919 // maps to a 2x3 texture rectangle with normalized coordinates
1924 // stores abs(dir.xy), offset.xy/2.5
1925 unsigned char data[4*6] =
1927 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1928 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1929 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1930 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1931 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1932 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1934 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1937 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1941 float nearclip, farclip, bias;
1942 r_viewport_t viewport;
1945 maxsize = r_shadow_shadowmapmaxsize;
1946 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1948 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1949 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1950 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1951 r_shadow_shadowmapside = side;
1952 r_shadow_shadowmapsize = size;
1953 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
1955 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1956 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1957 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1958 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1960 // complex unrolled cube approach (more flexible)
1961 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1962 R_Shadow_MakeVSDCT();
1963 if (!r_shadow_shadowmap2dtexture)
1966 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1967 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
1968 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1969 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1970 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1971 // render depth into the fbo, do not render color at all
1972 qglDrawBuffer(GL_NONE);CHECKGLERROR
1973 qglReadBuffer(GL_NONE);CHECKGLERROR
1974 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1975 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1977 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1978 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1983 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1984 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1985 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1986 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1988 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
1990 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1991 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1992 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1993 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1995 // complex unrolled cube approach (more flexible)
1996 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1997 R_Shadow_MakeVSDCT();
1998 if (!r_shadow_shadowmaprectangletexture)
2001 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2002 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2003 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2004 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2005 // render depth into the fbo, do not render color at all
2006 qglDrawBuffer(GL_NONE);CHECKGLERROR
2007 qglReadBuffer(GL_NONE);CHECKGLERROR
2008 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2009 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2011 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2012 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2017 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2018 r_shadow_shadowmap_texturescale[0] = 1.0f;
2019 r_shadow_shadowmap_texturescale[1] = 1.0f;
2020 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2022 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2024 r_shadow_shadowmap_parameters[0] = 1.0f;
2025 r_shadow_shadowmap_parameters[1] = 1.0f;
2026 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2027 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2029 // simple cube approach
2030 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2033 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2034 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2035 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2036 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
2037 // render depth into the fbo, do not render color at all
2038 qglDrawBuffer(GL_NONE);CHECKGLERROR
2039 qglReadBuffer(GL_NONE);CHECKGLERROR
2040 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2041 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2043 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2044 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2049 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2050 r_shadow_shadowmap_texturescale[0] = 0.0f;
2051 r_shadow_shadowmap_texturescale[1] = 0.0f;
2052 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2055 R_Shadow_RenderMode_Reset();
2058 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2059 R_SetupDepthOrShadowShader();
2063 R_SetupShowDepthShader();
2064 qglClearColor(1,1,1,1);CHECKGLERROR
2067 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2074 R_SetViewport(&viewport);
2075 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2076 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2078 int flipped = (side&1)^(side>>2);
2079 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2080 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2081 GL_CullFace(r_refdef.view.cullface_back);
2083 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2085 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
2088 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2092 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2096 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2097 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2098 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2099 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2102 R_Shadow_RenderMode_Reset();
2103 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2106 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2110 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2111 // only draw light where this geometry was already rendered AND the
2112 // stencil is 128 (values other than this mean shadow)
2113 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2115 r_shadow_rendermode = r_shadow_lightingrendermode;
2116 // do global setup needed for the chosen lighting mode
2117 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2119 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2120 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2124 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2126 r_shadow_usingshadowmap2d = true;
2127 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2130 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2132 r_shadow_usingshadowmaprect = true;
2133 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2136 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2138 r_shadow_usingshadowmapcube = true;
2139 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2143 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2145 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2150 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2151 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2152 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2156 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2159 R_Shadow_RenderMode_Reset();
2160 GL_BlendFunc(GL_ONE, GL_ONE);
2161 GL_DepthRange(0, 1);
2162 GL_DepthTest(r_showshadowvolumes.integer < 2);
2163 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2164 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2165 GL_CullFace(GL_NONE);
2166 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2169 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2172 R_Shadow_RenderMode_Reset();
2173 GL_BlendFunc(GL_ONE, GL_ONE);
2174 GL_DepthRange(0, 1);
2175 GL_DepthTest(r_showlighting.integer < 2);
2176 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2179 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2183 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2184 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2186 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2189 void R_Shadow_RenderMode_End(void)
2192 R_Shadow_RenderMode_Reset();
2193 R_Shadow_RenderMode_ActiveLight(NULL);
2195 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2196 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2199 int bboxedges[12][2] =
2218 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2220 int i, ix1, iy1, ix2, iy2;
2221 float x1, y1, x2, y2;
2223 float vertex[20][3];
2232 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2233 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2234 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2235 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2237 if (!r_shadow_scissor.integer)
2240 // if view is inside the light box, just say yes it's visible
2241 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2244 x1 = y1 = x2 = y2 = 0;
2246 // transform all corners that are infront of the nearclip plane
2247 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2248 plane4f[3] = r_refdef.view.frustum[4].dist;
2250 for (i = 0;i < 8;i++)
2252 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2253 dist[i] = DotProduct4(corner[i], plane4f);
2254 sign[i] = dist[i] > 0;
2257 VectorCopy(corner[i], vertex[numvertices]);
2261 // if some points are behind the nearclip, add clipped edge points to make
2262 // sure that the scissor boundary is complete
2263 if (numvertices > 0 && numvertices < 8)
2265 // add clipped edge points
2266 for (i = 0;i < 12;i++)
2268 j = bboxedges[i][0];
2269 k = bboxedges[i][1];
2270 if (sign[j] != sign[k])
2272 f = dist[j] / (dist[j] - dist[k]);
2273 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2279 // if we have no points to check, the light is behind the view plane
2283 // if we have some points to transform, check what screen area is covered
2284 x1 = y1 = x2 = y2 = 0;
2286 //Con_Printf("%i vertices to transform...\n", numvertices);
2287 for (i = 0;i < numvertices;i++)
2289 VectorCopy(vertex[i], v);
2290 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2291 //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]);
2294 if (x1 > v2[0]) x1 = v2[0];
2295 if (x2 < v2[0]) x2 = v2[0];
2296 if (y1 > v2[1]) y1 = v2[1];
2297 if (y2 < v2[1]) y2 = v2[1];
2306 // now convert the scissor rectangle to integer screen coordinates
2307 ix1 = (int)(x1 - 1.0f);
2308 iy1 = vid.height - (int)(y2 - 1.0f);
2309 ix2 = (int)(x2 + 1.0f);
2310 iy2 = vid.height - (int)(y1 + 1.0f);
2311 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2313 // clamp it to the screen
2314 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2315 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2316 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2317 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2319 // if it is inside out, it's not visible
2320 if (ix2 <= ix1 || iy2 <= iy1)
2323 // the light area is visible, set up the scissor rectangle
2324 r_shadow_lightscissor[0] = ix1;
2325 r_shadow_lightscissor[1] = iy1;
2326 r_shadow_lightscissor[2] = ix2 - ix1;
2327 r_shadow_lightscissor[3] = iy2 - iy1;
2329 r_refdef.stats.lights_scissored++;
2333 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2335 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2336 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2337 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2338 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2339 if (r_textureunits.integer >= 3)
2341 if (VectorLength2(diffusecolor) > 0)
2343 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2345 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2346 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2347 if ((dot = DotProduct(n, v)) < 0)
2349 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2350 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2353 VectorCopy(ambientcolor, color4f);
2354 if (r_refdef.fogenabled)
2357 f = RSurf_FogVertex(vertex3f);
2358 VectorScale(color4f, f, color4f);
2365 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2367 VectorCopy(ambientcolor, color4f);
2368 if (r_refdef.fogenabled)
2371 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2372 f = RSurf_FogVertex(vertex3f);
2373 VectorScale(color4f, f, color4f);
2379 else if (r_textureunits.integer >= 2)
2381 if (VectorLength2(diffusecolor) > 0)
2383 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2385 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2386 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2388 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2389 if ((dot = DotProduct(n, v)) < 0)
2391 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2392 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2393 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2394 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2398 color4f[0] = ambientcolor[0] * distintensity;
2399 color4f[1] = ambientcolor[1] * distintensity;
2400 color4f[2] = ambientcolor[2] * distintensity;
2402 if (r_refdef.fogenabled)
2405 f = RSurf_FogVertex(vertex3f);
2406 VectorScale(color4f, f, color4f);
2410 VectorClear(color4f);
2416 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2418 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2419 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2421 color4f[0] = ambientcolor[0] * distintensity;
2422 color4f[1] = ambientcolor[1] * distintensity;
2423 color4f[2] = ambientcolor[2] * distintensity;
2424 if (r_refdef.fogenabled)
2427 f = RSurf_FogVertex(vertex3f);
2428 VectorScale(color4f, f, color4f);
2432 VectorClear(color4f);
2439 if (VectorLength2(diffusecolor) > 0)
2441 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2443 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2444 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2446 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2447 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2448 if ((dot = DotProduct(n, v)) < 0)
2450 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2451 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2452 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2453 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2457 color4f[0] = ambientcolor[0] * distintensity;
2458 color4f[1] = ambientcolor[1] * distintensity;
2459 color4f[2] = ambientcolor[2] * distintensity;
2461 if (r_refdef.fogenabled)
2464 f = RSurf_FogVertex(vertex3f);
2465 VectorScale(color4f, f, color4f);
2469 VectorClear(color4f);
2475 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2477 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2478 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2480 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2481 color4f[0] = ambientcolor[0] * distintensity;
2482 color4f[1] = ambientcolor[1] * distintensity;
2483 color4f[2] = ambientcolor[2] * distintensity;
2484 if (r_refdef.fogenabled)
2487 f = RSurf_FogVertex(vertex3f);
2488 VectorScale(color4f, f, color4f);
2492 VectorClear(color4f);
2499 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2501 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2504 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2505 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2506 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2507 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2508 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2510 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2512 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2513 // the cubemap normalizes this for us
2514 out3f[0] = DotProduct(svector3f, lightdir);
2515 out3f[1] = DotProduct(tvector3f, lightdir);
2516 out3f[2] = DotProduct(normal3f, lightdir);
2520 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2523 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2524 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2525 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2526 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2527 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2528 float lightdir[3], eyedir[3], halfdir[3];
2529 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2531 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2532 VectorNormalize(lightdir);
2533 VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir);
2534 VectorNormalize(eyedir);
2535 VectorAdd(lightdir, eyedir, halfdir);
2536 // the cubemap normalizes this for us
2537 out3f[0] = DotProduct(svector3f, halfdir);
2538 out3f[1] = DotProduct(tvector3f, halfdir);
2539 out3f[2] = DotProduct(normal3f, halfdir);
2543 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)
2545 // used to display how many times a surface is lit for level design purposes
2546 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2549 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)
2551 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2552 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2553 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2554 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2556 R_Mesh_ColorPointer(NULL, 0, 0);
2557 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2558 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2559 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2560 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2561 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2562 if (rsurface.texture->backgroundcurrentskinframe)
2564 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2565 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2566 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2567 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2569 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2570 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2571 if(rsurface.texture->colormapping)
2573 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2574 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2576 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2577 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2578 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2579 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2580 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2581 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2583 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2585 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2586 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2588 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2592 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)
2594 // shared final code for all the dot3 layers
2596 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2597 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2599 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2600 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2604 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)
2607 // colorscale accounts for how much we multiply the brightness
2610 // mult is how many times the final pass of the lighting will be
2611 // performed to get more brightness than otherwise possible.
2613 // Limit mult to 64 for sanity sake.
2615 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2617 // 3 3D combine path (Geforce3, Radeon 8500)
2618 memset(&m, 0, sizeof(m));
2619 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2620 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2621 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2622 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2623 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2624 m.tex[1] = R_GetTexture(basetexture);
2625 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2626 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2627 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2628 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2629 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2630 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2631 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2632 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2633 m.texmatrix[2] = rsurface.entitytolight;
2634 GL_BlendFunc(GL_ONE, GL_ONE);
2636 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2638 // 2 3D combine path (Geforce3, original Radeon)
2639 memset(&m, 0, sizeof(m));
2640 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2641 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2642 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2643 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2644 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2645 m.tex[1] = R_GetTexture(basetexture);
2646 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2647 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2648 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2649 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2650 GL_BlendFunc(GL_ONE, GL_ONE);
2652 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2654 // 4 2D combine path (Geforce3, Radeon 8500)
2655 memset(&m, 0, sizeof(m));
2656 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2657 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2658 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2659 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2660 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2661 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2662 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2663 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2664 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2665 m.texmatrix[1] = rsurface.entitytoattenuationz;
2666 m.tex[2] = R_GetTexture(basetexture);
2667 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2668 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2669 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2670 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2671 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2673 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2674 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2675 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2676 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2677 m.texmatrix[3] = rsurface.entitytolight;
2679 GL_BlendFunc(GL_ONE, GL_ONE);
2681 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2683 // 3 2D combine path (Geforce3, original Radeon)
2684 memset(&m, 0, sizeof(m));
2685 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2686 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2687 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2688 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2689 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2690 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2691 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2692 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2693 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2694 m.texmatrix[1] = rsurface.entitytoattenuationz;
2695 m.tex[2] = R_GetTexture(basetexture);
2696 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2697 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2698 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2699 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2700 GL_BlendFunc(GL_ONE, GL_ONE);
2704 // 2/2/2 2D combine path (any dot3 card)
2705 memset(&m, 0, sizeof(m));
2706 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2707 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2708 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2709 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2710 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2711 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2712 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2713 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2714 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2715 m.texmatrix[1] = rsurface.entitytoattenuationz;
2716 R_Mesh_TextureState(&m);
2717 GL_ColorMask(0,0,0,1);
2718 GL_BlendFunc(GL_ONE, GL_ZERO);
2719 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2722 memset(&m, 0, sizeof(m));
2723 m.tex[0] = R_GetTexture(basetexture);
2724 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2725 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2726 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2727 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2728 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2730 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2731 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2732 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2733 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2734 m.texmatrix[1] = rsurface.entitytolight;
2736 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2738 // this final code is shared
2739 R_Mesh_TextureState(&m);
2740 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);
2743 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)
2746 // colorscale accounts for how much we multiply the brightness
2749 // mult is how many times the final pass of the lighting will be
2750 // performed to get more brightness than otherwise possible.
2752 // Limit mult to 64 for sanity sake.
2754 // generate normalization cubemap texcoords
2755 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2756 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2758 // 3/2 3D combine path (Geforce3, Radeon 8500)
2759 memset(&m, 0, sizeof(m));
2760 m.tex[0] = R_GetTexture(normalmaptexture);
2761 m.texcombinergb[0] = GL_REPLACE;
2762 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2763 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2764 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2765 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2766 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2767 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2768 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2769 m.pointer_texcoord_bufferobject[1] = 0;
2770 m.pointer_texcoord_bufferoffset[1] = 0;
2771 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2772 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2773 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2774 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2775 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2776 R_Mesh_TextureState(&m);
2777 GL_ColorMask(0,0,0,1);
2778 GL_BlendFunc(GL_ONE, GL_ZERO);
2779 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2782 memset(&m, 0, sizeof(m));
2783 m.tex[0] = R_GetTexture(basetexture);
2784 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2785 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2786 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2787 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2788 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2790 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2791 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2792 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2793 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2794 m.texmatrix[1] = rsurface.entitytolight;
2796 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2798 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2800 // 1/2/2 3D combine path (original Radeon)
2801 memset(&m, 0, sizeof(m));
2802 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2803 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2804 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2805 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2806 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2807 R_Mesh_TextureState(&m);
2808 GL_ColorMask(0,0,0,1);
2809 GL_BlendFunc(GL_ONE, GL_ZERO);
2810 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2813 memset(&m, 0, sizeof(m));
2814 m.tex[0] = R_GetTexture(normalmaptexture);
2815 m.texcombinergb[0] = GL_REPLACE;
2816 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2817 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2818 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2819 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2820 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2821 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2822 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2823 m.pointer_texcoord_bufferobject[1] = 0;
2824 m.pointer_texcoord_bufferoffset[1] = 0;
2825 R_Mesh_TextureState(&m);
2826 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2827 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2830 memset(&m, 0, sizeof(m));
2831 m.tex[0] = R_GetTexture(basetexture);
2832 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2833 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2834 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2835 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2836 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2838 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2839 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2840 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2841 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2842 m.texmatrix[1] = rsurface.entitytolight;
2844 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2846 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2848 // 2/2 3D combine path (original Radeon)
2849 memset(&m, 0, sizeof(m));
2850 m.tex[0] = R_GetTexture(normalmaptexture);
2851 m.texcombinergb[0] = GL_REPLACE;
2852 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2853 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2854 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2855 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2856 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2857 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2858 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2859 m.pointer_texcoord_bufferobject[1] = 0;
2860 m.pointer_texcoord_bufferoffset[1] = 0;
2861 R_Mesh_TextureState(&m);
2862 GL_ColorMask(0,0,0,1);
2863 GL_BlendFunc(GL_ONE, GL_ZERO);
2864 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2867 memset(&m, 0, sizeof(m));
2868 m.tex[0] = R_GetTexture(basetexture);
2869 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2870 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2871 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2872 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2873 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2874 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2875 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2876 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2877 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2878 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2880 else if (r_textureunits.integer >= 4)
2882 // 4/2 2D combine path (Geforce3, Radeon 8500)
2883 memset(&m, 0, sizeof(m));
2884 m.tex[0] = R_GetTexture(normalmaptexture);
2885 m.texcombinergb[0] = GL_REPLACE;
2886 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2887 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2888 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2889 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2890 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2891 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2892 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2893 m.pointer_texcoord_bufferobject[1] = 0;
2894 m.pointer_texcoord_bufferoffset[1] = 0;
2895 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2896 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2897 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2898 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2899 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2900 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2901 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2902 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2903 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2904 m.texmatrix[3] = rsurface.entitytoattenuationz;
2905 R_Mesh_TextureState(&m);
2906 GL_ColorMask(0,0,0,1);
2907 GL_BlendFunc(GL_ONE, GL_ZERO);
2908 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2911 memset(&m, 0, sizeof(m));
2912 m.tex[0] = R_GetTexture(basetexture);
2913 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2914 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2915 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2916 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2917 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2919 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2920 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2921 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2922 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2923 m.texmatrix[1] = rsurface.entitytolight;
2925 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2929 // 2/2/2 2D combine path (any dot3 card)
2930 memset(&m, 0, sizeof(m));
2931 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2932 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2933 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2934 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2935 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2936 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2937 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2938 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2939 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2940 m.texmatrix[1] = rsurface.entitytoattenuationz;
2941 R_Mesh_TextureState(&m);
2942 GL_ColorMask(0,0,0,1);
2943 GL_BlendFunc(GL_ONE, GL_ZERO);
2944 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2947 memset(&m, 0, sizeof(m));
2948 m.tex[0] = R_GetTexture(normalmaptexture);
2949 m.texcombinergb[0] = GL_REPLACE;
2950 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2951 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2952 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2953 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2954 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2955 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2956 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2957 m.pointer_texcoord_bufferobject[1] = 0;
2958 m.pointer_texcoord_bufferoffset[1] = 0;
2959 R_Mesh_TextureState(&m);
2960 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2961 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2964 memset(&m, 0, sizeof(m));
2965 m.tex[0] = R_GetTexture(basetexture);
2966 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2967 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2968 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2969 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2970 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2972 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2973 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2974 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2975 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2976 m.texmatrix[1] = rsurface.entitytolight;
2978 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2980 // this final code is shared
2981 R_Mesh_TextureState(&m);
2982 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);
2985 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)
2987 float glossexponent;
2989 // FIXME: detect blendsquare!
2990 //if (!gl_support_blendsquare)
2993 // generate normalization cubemap texcoords
2994 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2995 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2997 // 2/0/0/1/2 3D combine blendsquare path
2998 memset(&m, 0, sizeof(m));
2999 m.tex[0] = R_GetTexture(normalmaptexture);
3000 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3001 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3002 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3003 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3004 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3005 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3006 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3007 m.pointer_texcoord_bufferobject[1] = 0;
3008 m.pointer_texcoord_bufferoffset[1] = 0;
3009 R_Mesh_TextureState(&m);
3010 GL_ColorMask(0,0,0,1);
3011 // this squares the result
3012 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3013 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3015 // second and third pass
3016 R_Mesh_ResetTextureState();
3017 // square alpha in framebuffer a few times to make it shiny
3018 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3019 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3020 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3023 memset(&m, 0, sizeof(m));
3024 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3025 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3026 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3027 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3028 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3029 R_Mesh_TextureState(&m);
3030 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3031 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3034 memset(&m, 0, sizeof(m));
3035 m.tex[0] = R_GetTexture(glosstexture);
3036 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3037 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3038 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3039 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3040 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3042 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3043 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3044 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3045 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3046 m.texmatrix[1] = rsurface.entitytolight;
3048 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3050 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3052 // 2/0/0/2 3D combine blendsquare path
3053 memset(&m, 0, sizeof(m));
3054 m.tex[0] = R_GetTexture(normalmaptexture);
3055 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3056 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3057 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3058 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3059 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3060 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3061 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3062 m.pointer_texcoord_bufferobject[1] = 0;
3063 m.pointer_texcoord_bufferoffset[1] = 0;
3064 R_Mesh_TextureState(&m);
3065 GL_ColorMask(0,0,0,1);
3066 // this squares the result
3067 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3068 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3070 // second and third pass
3071 R_Mesh_ResetTextureState();
3072 // square alpha in framebuffer a few times to make it shiny
3073 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3074 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3075 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3078 memset(&m, 0, sizeof(m));
3079 m.tex[0] = R_GetTexture(glosstexture);
3080 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3081 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3082 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3083 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3084 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3085 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3086 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3087 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3088 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3089 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3093 // 2/0/0/2/2 2D combine blendsquare path
3094 memset(&m, 0, sizeof(m));
3095 m.tex[0] = R_GetTexture(normalmaptexture);
3096 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3097 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3098 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3099 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3100 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3101 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3102 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3103 m.pointer_texcoord_bufferobject[1] = 0;
3104 m.pointer_texcoord_bufferoffset[1] = 0;
3105 R_Mesh_TextureState(&m);
3106 GL_ColorMask(0,0,0,1);
3107 // this squares the result
3108 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3109 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3111 // second and third pass
3112 R_Mesh_ResetTextureState();
3113 // square alpha in framebuffer a few times to make it shiny
3114 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3115 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3116 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3119 memset(&m, 0, sizeof(m));
3120 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3121 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3122 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3123 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3124 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3125 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3126 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3127 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3128 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3129 m.texmatrix[1] = rsurface.entitytoattenuationz;
3130 R_Mesh_TextureState(&m);
3131 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3132 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3135 memset(&m, 0, sizeof(m));
3136 m.tex[0] = R_GetTexture(glosstexture);
3137 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3138 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3139 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3140 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3141 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3143 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3144 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3145 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3146 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3147 m.texmatrix[1] = rsurface.entitytolight;
3149 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3151 // this final code is shared
3152 R_Mesh_TextureState(&m);
3153 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);
3156 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)
3158 // ARB path (any Geforce, any Radeon)
3159 qboolean doambient = ambientscale > 0;
3160 qboolean dodiffuse = diffusescale > 0;
3161 qboolean dospecular = specularscale > 0;
3162 if (!doambient && !dodiffuse && !dospecular)
3164 R_Mesh_ColorPointer(NULL, 0, 0);
3166 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3168 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3172 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3174 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3179 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3181 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3184 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3187 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3194 int newnumtriangles;
3198 int maxtriangles = 4096;
3199 int newelements[4096*3];
3200 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3201 for (renders = 0;renders < 64;renders++)
3206 newnumtriangles = 0;
3208 // due to low fillrate on the cards this vertex lighting path is
3209 // designed for, we manually cull all triangles that do not
3210 // contain a lit vertex
3211 // this builds batches of triangles from multiple surfaces and
3212 // renders them at once
3213 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3215 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3217 if (newnumtriangles)
3219 newfirstvertex = min(newfirstvertex, e[0]);
3220 newlastvertex = max(newlastvertex, e[0]);
3224 newfirstvertex = e[0];
3225 newlastvertex = e[0];
3227 newfirstvertex = min(newfirstvertex, e[1]);
3228 newlastvertex = max(newlastvertex, e[1]);
3229 newfirstvertex = min(newfirstvertex, e[2]);
3230 newlastvertex = max(newlastvertex, e[2]);
3236 if (newnumtriangles >= maxtriangles)
3238 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3239 newnumtriangles = 0;
3245 if (newnumtriangles >= 1)
3247 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3250 // if we couldn't find any lit triangles, exit early
3253 // now reduce the intensity for the next overbright pass
3254 // we have to clamp to 0 here incase the drivers have improper
3255 // handling of negative colors
3256 // (some old drivers even have improper handling of >1 color)
3258 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3260 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3262 c[0] = max(0, c[0] - 1);
3263 c[1] = max(0, c[1] - 1);
3264 c[2] = max(0, c[2] - 1);
3276 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)
3278 // OpenGL 1.1 path (anything)
3279 float ambientcolorbase[3], diffusecolorbase[3];
3280 float ambientcolorpants[3], diffusecolorpants[3];
3281 float ambientcolorshirt[3], diffusecolorshirt[3];
3283 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3284 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3285 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3286 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3287 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3288 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3289 memset(&m, 0, sizeof(m));
3290 m.tex[0] = R_GetTexture(basetexture);
3291 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3292 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3293 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3294 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3295 if (r_textureunits.integer >= 2)
3298 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3299 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3300 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3301 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3302 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3303 if (r_textureunits.integer >= 3)
3305 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3306 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3307 m.texmatrix[2] = rsurface.entitytoattenuationz;
3308 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3309 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3310 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3313 R_Mesh_TextureState(&m);
3314 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3315 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3318 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3319 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3323 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3324 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3328 extern cvar_t gl_lightmaps;
3329 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)
3331 float ambientscale, diffusescale, specularscale;
3333 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3335 // calculate colors to render this texture with
3336 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3337 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3338 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3339 ambientscale = rsurface.rtlight->ambientscale;
3340 diffusescale = rsurface.rtlight->diffusescale;
3341 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3342 if (!r_shadow_usenormalmap.integer)
3344 ambientscale += 1.0f * diffusescale;
3348 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3350 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && gl_support_ext_blend_subtract;
3353 VectorNegate(lightcolorbase, lightcolorbase);
3354 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3356 RSurf_SetupDepthAndCulling();
3357 nmap = rsurface.texture->currentskinframe->nmap;
3358 if (gl_lightmaps.integer)
3359 nmap = r_texture_blanknormalmap;
3360 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3362 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3363 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3366 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3367 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3368 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3371 VectorClear(lightcolorpants);
3374 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3375 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3376 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3379 VectorClear(lightcolorshirt);
3380 switch (r_shadow_rendermode)
3382 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3383 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3384 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);
3386 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3387 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);
3389 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3390 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);
3392 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3393 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);
3396 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3402 switch (r_shadow_rendermode)
3404 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3405 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3406 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);
3408 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3409 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);
3411 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3412 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);
3414 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3415 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);
3418 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3423 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3426 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)
3428 matrix4x4_t tempmatrix = *matrix;
3429 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3431 // if this light has been compiled before, free the associated data
3432 R_RTLight_Uncompile(rtlight);
3434 // clear it completely to avoid any lingering data
3435 memset(rtlight, 0, sizeof(*rtlight));
3437 // copy the properties
3438 rtlight->matrix_lighttoworld = tempmatrix;
3439 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3440 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3441 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3442 VectorCopy(color, rtlight->color);
3443 rtlight->cubemapname[0] = 0;
3444 if (cubemapname && cubemapname[0])
3445 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3446 rtlight->shadow = shadow;
3447 rtlight->corona = corona;
3448 rtlight->style = style;
3449 rtlight->isstatic = isstatic;
3450 rtlight->coronasizescale = coronasizescale;
3451 rtlight->ambientscale = ambientscale;
3452 rtlight->diffusescale = diffusescale;
3453 rtlight->specularscale = specularscale;
3454 rtlight->flags = flags;
3456 // compute derived data
3457 //rtlight->cullradius = rtlight->radius;
3458 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3459 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3460 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3461 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3462 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3463 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3464 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3467 // compiles rtlight geometry
3468 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3469 void R_RTLight_Compile(rtlight_t *rtlight)
3472 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3473 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3474 entity_render_t *ent = r_refdef.scene.worldentity;
3475 dp_model_t *model = r_refdef.scene.worldmodel;
3476 unsigned char *data;
3479 // compile the light
3480 rtlight->compiled = true;
3481 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3482 rtlight->static_numleafs = 0;
3483 rtlight->static_numleafpvsbytes = 0;
3484 rtlight->static_leaflist = NULL;
3485 rtlight->static_leafpvs = NULL;
3486 rtlight->static_numsurfaces = 0;
3487 rtlight->static_surfacelist = NULL;
3488 rtlight->static_shadowmap_receivers = 0x3F;
3489 rtlight->static_shadowmap_casters = 0x3F;
3490 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3491 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3492 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3493 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3494 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3495 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3497 if (model && model->GetLightInfo)
3499 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3500 r_shadow_compilingrtlight = rtlight;
3501 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);
3502 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);
3503 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3504 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3505 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3506 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3507 rtlight->static_numsurfaces = numsurfaces;
3508 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3509 rtlight->static_numleafs = numleafs;
3510 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3511 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3512 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3513 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3514 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3515 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3516 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3517 if (rtlight->static_numsurfaces)
3518 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3519 if (rtlight->static_numleafs)
3520 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3521 if (rtlight->static_numleafpvsbytes)
3522 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3523 if (rtlight->static_numshadowtrispvsbytes)
3524 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3525 if (rtlight->static_numlighttrispvsbytes)
3526 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3527 switch (rtlight->shadowmode)
3529 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3530 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3531 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3532 if (model->CompileShadowMap && rtlight->shadow)
3533 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3536 if (model->CompileShadowVolume && rtlight->shadow)
3537 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3540 // now we're done compiling the rtlight
3541 r_shadow_compilingrtlight = NULL;
3545 // use smallest available cullradius - box radius or light radius
3546 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3547 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3549 shadowzpasstris = 0;
3550 if (rtlight->static_meshchain_shadow_zpass)
3551 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3552 shadowzpasstris += mesh->numtriangles;
3554 shadowzfailtris = 0;
3555 if (rtlight->static_meshchain_shadow_zfail)
3556 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3557 shadowzfailtris += mesh->numtriangles;
3560 if (rtlight->static_numlighttrispvsbytes)
3561 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3562 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3566 if (rtlight->static_numlighttrispvsbytes)
3567 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3568 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3571 if (developer.integer >= 10)
3572 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);
3575 void R_RTLight_Uncompile(rtlight_t *rtlight)
3577 if (rtlight->compiled)
3579 if (rtlight->static_meshchain_shadow_zpass)
3580 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3581 rtlight->static_meshchain_shadow_zpass = NULL;
3582 if (rtlight->static_meshchain_shadow_zfail)
3583 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3584 rtlight->static_meshchain_shadow_zfail = NULL;
3585 if (rtlight->static_meshchain_shadow_shadowmap)
3586 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3587 rtlight->static_meshchain_shadow_shadowmap = NULL;
3588 // these allocations are grouped
3589 if (rtlight->static_surfacelist)
3590 Mem_Free(rtlight->static_surfacelist);
3591 rtlight->static_numleafs = 0;
3592 rtlight->static_numleafpvsbytes = 0;
3593 rtlight->static_leaflist = NULL;
3594 rtlight->static_leafpvs = NULL;
3595 rtlight->static_numsurfaces = 0;
3596 rtlight->static_surfacelist = NULL;
3597 rtlight->static_numshadowtrispvsbytes = 0;
3598 rtlight->static_shadowtrispvs = NULL;
3599 rtlight->static_numlighttrispvsbytes = 0;
3600 rtlight->static_lighttrispvs = NULL;
3601 rtlight->compiled = false;
3605 void R_Shadow_UncompileWorldLights(void)
3609 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3610 for (lightindex = 0;lightindex < range;lightindex++)
3612 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3615 R_RTLight_Uncompile(&light->rtlight);
3619 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3623 // reset the count of frustum planes
3624 // see rsurface.rtlight_frustumplanes definition for how much this array
3626 rsurface.rtlight_numfrustumplanes = 0;
3628 // haven't implemented a culling path for ortho rendering
3629 if (!r_refdef.view.useperspective)
3631 // check if the light is on screen and copy the 4 planes if it is
3632 for (i = 0;i < 4;i++)
3633 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3636 for (i = 0;i < 4;i++)
3637 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3642 // generate a deformed frustum that includes the light origin, this is
3643 // used to cull shadow casting surfaces that can not possibly cast a
3644 // shadow onto the visible light-receiving surfaces, which can be a
3647 // if the light origin is onscreen the result will be 4 planes exactly
3648 // if the light origin is offscreen on only one axis the result will
3649 // be exactly 5 planes (split-side case)
3650 // if the light origin is offscreen on two axes the result will be
3651 // exactly 4 planes (stretched corner case)
3652 for (i = 0;i < 4;i++)
3654 // quickly reject standard frustum planes that put the light
3655 // origin outside the frustum
3656 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3659 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3661 // if all the standard frustum planes were accepted, the light is onscreen
3662 // otherwise we need to generate some more planes below...
3663 if (rsurface.rtlight_numfrustumplanes < 4)
3665 // at least one of the stock frustum planes failed, so we need to
3666 // create one or two custom planes to enclose the light origin
3667 for (i = 0;i < 4;i++)
3669 // create a plane using the view origin and light origin, and a
3670 // single point from the frustum corner set
3671 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3672 VectorNormalize(plane.normal);
3673 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3674 // see if this plane is backwards and flip it if so
3675 for (j = 0;j < 4;j++)
3676 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3680 VectorNegate(plane.normal, plane.normal);
3682 // flipped plane, test again to see if it is now valid
3683 for (j = 0;j < 4;j++)
3684 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3686 // if the plane is still not valid, then it is dividing the
3687 // frustum and has to be rejected
3691 // we have created a valid plane, compute extra info
3692 PlaneClassify(&plane);
3694 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3696 // if we've found 5 frustum planes then we have constructed a
3697 // proper split-side case and do not need to keep searching for
3698 // planes to enclose the light origin
3699 if (rsurface.rtlight_numfrustumplanes == 5)
3707 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3709 plane = rsurface.rtlight_frustumplanes[i];
3710 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));
3715 // now add the light-space box planes if the light box is rotated, as any
3716 // caster outside the oriented light box is irrelevant (even if it passed
3717 // the worldspace light box, which is axial)
3718 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3720 for (i = 0;i < 6;i++)
3724 v[i >> 1] = (i & 1) ? -1 : 1;
3725 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3726 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3727 plane.dist = VectorNormalizeLength(plane.normal);
3728 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3729 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3735 // add the world-space reduced box planes
3736 for (i = 0;i < 6;i++)
3738 VectorClear(plane.normal);
3739 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3740 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3741 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3750 // reduce all plane distances to tightly fit the rtlight cull box, which
3752 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3753 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3754 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3755 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3756 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3757 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3758 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3759 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3760 oldnum = rsurface.rtlight_numfrustumplanes;
3761 rsurface.rtlight_numfrustumplanes = 0;
3762 for (j = 0;j < oldnum;j++)
3764 // find the nearest point on the box to this plane
3765 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3766 for (i = 1;i < 8;i++)
3768 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3769 if (bestdist > dist)
3772 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);
3773 // if the nearest point is near or behind the plane, we want this
3774 // plane, otherwise the plane is useless as it won't cull anything
3775 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3777 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3778 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3785 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3789 RSurf_ActiveWorldEntity();
3791 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3794 GL_CullFace(GL_NONE);
3795 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3796 for (;mesh;mesh = mesh->next)
3798 if (!mesh->sidetotals[r_shadow_shadowmapside])
3800 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3801 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3802 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3806 else if (r_refdef.scene.worldentity->model)
3807 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);
3809 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3812 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3817 int surfacelistindex;
3818 msurface_t *surface;
3820 RSurf_ActiveWorldEntity();
3822 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3825 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3826 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3827 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3828 for (;mesh;mesh = mesh->next)
3830 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3831 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3832 GL_LockArrays(0, mesh->numverts);
3833 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3835 // increment stencil if frontface is infront of depthbuffer
3836 GL_CullFace(r_refdef.view.cullface_back);
3837 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3838 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3839 // decrement stencil if backface is infront of depthbuffer
3840 GL_CullFace(r_refdef.view.cullface_front);
3841 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3843 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3845 // decrement stencil if backface is behind depthbuffer
3846 GL_CullFace(r_refdef.view.cullface_front);
3847 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3848 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3849 // increment stencil if frontface is behind depthbuffer
3850 GL_CullFace(r_refdef.view.cullface_back);
3851 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3853 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3854 GL_LockArrays(0, 0);
3858 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3860 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3861 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3863 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3864 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3865 if (CHECKPVSBIT(trispvs, t))
3866 shadowmarklist[numshadowmark++] = t;
3868 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);
3870 else if (numsurfaces)
3871 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3873 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3876 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3878 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3879 vec_t relativeshadowradius;
3880 RSurf_ActiveModelEntity(ent, false, false);
3881 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3882 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3883 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3884 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3885 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3886 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3887 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3888 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3889 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3891 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3894 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3895 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3898 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3900 // set up properties for rendering light onto this entity
3901 RSurf_ActiveModelEntity(ent, true, true);
3902 GL_AlphaTest(false);
3903 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3904 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3905 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3906 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3907 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3908 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3911 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3913 if (!r_refdef.scene.worldmodel->DrawLight)
3916 // set up properties for rendering light onto this entity
3917 RSurf_ActiveWorldEntity();
3918 GL_AlphaTest(false);
3919 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3920 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3921 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3922 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3923 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3924 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3926 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3928 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3931 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3933 dp_model_t *model = ent->model;
3934 if (!model->DrawLight)
3937 R_Shadow_SetupEntityLight(ent);
3939 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3941 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3944 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3948 int numleafs, numsurfaces;
3949 int *leaflist, *surfacelist;
3950 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3951 int numlightentities;
3952 int numlightentities_noselfshadow;
3953 int numshadowentities;
3954 int numshadowentities_noselfshadow;
3955 static entity_render_t *lightentities[MAX_EDICTS];
3956 static entity_render_t *shadowentities[MAX_EDICTS];
3957 static unsigned char entitysides[MAX_EDICTS];
3958 int lightentities_noselfshadow;
3959 int shadowentities_noselfshadow;
3960 vec3_t nearestpoint;
3962 qboolean castshadows;
3965 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3966 // skip lights that are basically invisible (color 0 0 0)
3967 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3970 // loading is done before visibility checks because loading should happen
3971 // all at once at the start of a level, not when it stalls gameplay.
3972 // (especially important to benchmarks)
3974 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3976 if (rtlight->compiled)
3977 R_RTLight_Uncompile(rtlight);
3978 R_RTLight_Compile(rtlight);
3982 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3984 // look up the light style value at this time
3985 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3986 VectorScale(rtlight->color, f, rtlight->currentcolor);
3988 if (rtlight->selected)
3990 f = 2 + sin(realtime * M_PI * 4.0);
3991 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3995 // if lightstyle is currently off, don't draw the light
3996 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3999 // if the light box is offscreen, skip it
4000 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4003 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
4004 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
4006 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4008 // compiled light, world available and can receive realtime lighting
4009 // retrieve leaf information
4010 numleafs = rtlight->static_numleafs;
4011 leaflist = rtlight->static_leaflist;
4012 leafpvs = rtlight->static_leafpvs;
4013 numsurfaces = rtlight->static_numsurfaces;
4014 surfacelist = rtlight->static_surfacelist;
4015 surfacesides = NULL;
4016 shadowtrispvs = rtlight->static_shadowtrispvs;
4017 lighttrispvs = rtlight->static_lighttrispvs;
4019 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4021 // dynamic light, world available and can receive realtime lighting
4022 // calculate lit surfaces and leafs
4023 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);
4024 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);
4025 leaflist = r_shadow_buffer_leaflist;
4026 leafpvs = r_shadow_buffer_leafpvs;
4027 surfacelist = r_shadow_buffer_surfacelist;
4028 surfacesides = r_shadow_buffer_surfacesides;
4029 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4030 lighttrispvs = r_shadow_buffer_lighttrispvs;
4031 // if the reduced leaf bounds are offscreen, skip it
4032 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4043 surfacesides = NULL;
4044 shadowtrispvs = NULL;
4045 lighttrispvs = NULL;
4047 // check if light is illuminating any visible leafs
4050 for (i = 0;i < numleafs;i++)
4051 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4056 // set up a scissor rectangle for this light
4057 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4060 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4062 // make a list of lit entities and shadow casting entities
4063 numlightentities = 0;
4064 numlightentities_noselfshadow = 0;
4065 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4066 numshadowentities = 0;
4067 numshadowentities_noselfshadow = 0;
4068 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4070 // add dynamic entities that are lit by the light
4071 if (r_drawentities.integer)
4073 for (i = 0;i < r_refdef.scene.numentities;i++)
4076 entity_render_t *ent = r_refdef.scene.entities[i];
4078 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4080 // skip the object entirely if it is not within the valid
4081 // shadow-casting region (which includes the lit region)
4082 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4084 if (!(model = ent->model))
4086 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4088 // this entity wants to receive light, is visible, and is
4089 // inside the light box
4090 // TODO: check if the surfaces in the model can receive light
4091 // so now check if it's in a leaf seen by the light
4092 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))
4094 if (ent->flags & RENDER_NOSELFSHADOW)
4095 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4097 lightentities[numlightentities++] = ent;
4098 // since it is lit, it probably also casts a shadow...
4099 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4100 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4101 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4103 // note: exterior models without the RENDER_NOSELFSHADOW
4104 // flag still create a RENDER_NOSELFSHADOW shadow but
4105 // are lit normally, this means that they are
4106 // self-shadowing but do not shadow other
4107 // RENDER_NOSELFSHADOW entities such as the gun
4108 // (very weird, but keeps the player shadow off the gun)
4109 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4110 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4112 shadowentities[numshadowentities++] = ent;
4115 else if (ent->flags & RENDER_SHADOW)
4117 // this entity is not receiving light, but may still need to
4119 // TODO: check if the surfaces in the model can cast shadow
4120 // now check if it is in a leaf seen by the light
4121 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))
4123 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4124 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4125 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4127 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4128 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4130 shadowentities[numshadowentities++] = ent;
4136 // return if there's nothing at all to light
4137 if (!numlightentities && !numsurfaces)
4140 // don't let sound skip if going slow
4141 if (r_refdef.scene.extraupdate)
4144 // make this the active rtlight for rendering purposes
4145 R_Shadow_RenderMode_ActiveLight(rtlight);
4146 // count this light in the r_speeds
4147 r_refdef.stats.lights++;
4149 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4151 // optionally draw visible shape of the shadow volumes
4152 // for performance analysis by level designers
4153 R_Shadow_RenderMode_VisibleShadowVolumes();
4155 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4156 for (i = 0;i < numshadowentities;i++)
4157 R_Shadow_DrawEntityShadow(shadowentities[i]);
4158 for (i = 0;i < numshadowentities_noselfshadow;i++)
4159 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4162 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4164 // optionally draw the illuminated areas
4165 // for performance analysis by level designers
4166 R_Shadow_RenderMode_VisibleLighting(false, false);
4168 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4169 for (i = 0;i < numlightentities;i++)
4170 R_Shadow_DrawEntityLight(lightentities[i]);
4171 for (i = 0;i < numlightentities_noselfshadow;i++)
4172 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4175 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4177 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4178 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4179 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4180 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4182 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4183 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4184 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4186 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4192 int receivermask = 0;
4193 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4194 Matrix4x4_Abs(&radiustolight);
4196 r_shadow_shadowmaplod = 0;
4197 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4198 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4199 r_shadow_shadowmaplod = i;
4201 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
4202 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
4204 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4206 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4210 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4212 castermask = rtlight->static_shadowmap_casters;
4213 receivermask = rtlight->static_shadowmap_receivers;
4217 for(i = 0;i < numsurfaces;i++)
4219 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4220 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4221 castermask |= surfacesides[i];
4222 receivermask |= surfacesides[i];
4226 if (receivermask < 0x3F)
4228 for (i = 0;i < numlightentities;i++)
4229 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4230 if (receivermask < 0x3F)
4231 for(i = 0; i < numlightentities_noselfshadow;i++)
4232 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4235 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4239 for (i = 0;i < numshadowentities;i++)
4240 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4241 for (i = 0;i < numshadowentities_noselfshadow;i++)
4242 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4245 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4247 // render shadow casters into 6 sided depth texture
4248 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4250 R_Shadow_RenderMode_ShadowMap(side, true, size);
4251 if (! (castermask & (1 << side))) continue;
4253 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4254 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4255 R_Shadow_DrawEntityShadow(shadowentities[i]);
4258 if (numlightentities_noselfshadow)
4260 // render lighting using the depth texture as shadowmap
4261 // draw lighting in the unmasked areas
4262 R_Shadow_RenderMode_Lighting(false, false, true);
4263 for (i = 0;i < numlightentities_noselfshadow;i++)
4264 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4267 // render shadow casters into 6 sided depth texture
4268 if (numshadowentities_noselfshadow)
4270 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4272 R_Shadow_RenderMode_ShadowMap(side, false, size);
4273 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4274 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4278 // render lighting using the depth texture as shadowmap
4279 // draw lighting in the unmasked areas
4280 R_Shadow_RenderMode_Lighting(false, false, true);
4281 // draw lighting in the unmasked areas
4283 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4284 for (i = 0;i < numlightentities;i++)
4285 R_Shadow_DrawEntityLight(lightentities[i]);
4287 else if (castshadows && gl_stencil)
4289 // draw stencil shadow volumes to mask off pixels that are in shadow
4290 // so that they won't receive lighting
4291 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4292 R_Shadow_ClearStencil();
4294 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4295 for (i = 0;i < numshadowentities;i++)
4296 R_Shadow_DrawEntityShadow(shadowentities[i]);
4297 if (numlightentities_noselfshadow)
4299 // draw lighting in the unmasked areas
4300 R_Shadow_RenderMode_Lighting(true, false, false);
4301 for (i = 0;i < numlightentities_noselfshadow;i++)
4302 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4304 // optionally draw the illuminated areas
4305 // for performance analysis by level designers
4306 if (r_showlighting.integer && r_refdef.view.showdebug)
4308 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4309 for (i = 0;i < numlightentities_noselfshadow;i++)
4310 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4313 for (i = 0;i < numshadowentities_noselfshadow;i++)
4314 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4316 if (numsurfaces + numlightentities)
4318 // draw lighting in the unmasked areas
4319 R_Shadow_RenderMode_Lighting(true, false, false);
4321 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4322 for (i = 0;i < numlightentities;i++)
4323 R_Shadow_DrawEntityLight(lightentities[i]);
4328 if (numsurfaces + numlightentities)
4330 // draw lighting in the unmasked areas
4331 R_Shadow_RenderMode_Lighting(false, false, false);
4333 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4334 for (i = 0;i < numlightentities;i++)
4335 R_Shadow_DrawEntityLight(lightentities[i]);
4336 for (i = 0;i < numlightentities_noselfshadow;i++)
4337 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4342 void R_Shadow_DrawLightSprites(void);
4343 void R_ShadowVolumeLighting(qboolean visible)
4352 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4) ||
4353 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && gl_support_fragment_shader && gl_support_ext_framebuffer_object) ||
4354 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4355 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4356 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4357 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4358 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4359 R_Shadow_FreeShadowMaps();
4361 if (r_editlights.integer)
4362 R_Shadow_DrawLightSprites();
4364 R_Shadow_RenderMode_Begin();
4366 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4367 if (r_shadow_debuglight.integer >= 0)
4369 lightindex = r_shadow_debuglight.integer;
4370 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4371 if (light && (light->flags & flag))
4372 R_DrawRTLight(&light->rtlight, visible);
4376 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4377 for (lightindex = 0;lightindex < range;lightindex++)
4379 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4380 if (light && (light->flags & flag))
4381 R_DrawRTLight(&light->rtlight, visible);
4384 if (r_refdef.scene.rtdlight)
4386 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4387 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4389 else if(gl_flashblend.integer)
4391 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4393 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4394 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4395 VectorScale(rtlight->color, f, rtlight->currentcolor);
4399 R_Shadow_RenderMode_End();
4402 extern const float r_screenvertex3f[12];
4403 extern void R_SetupView(qboolean allowwaterclippingplane);
4404 extern void R_ResetViewRendering3D(void);
4405 extern void R_ResetViewRendering2D(void);
4406 extern cvar_t r_shadows;
4407 extern cvar_t r_shadows_darken;
4408 extern cvar_t r_shadows_drawafterrtlighting;
4409 extern cvar_t r_shadows_castfrombmodels;
4410 extern cvar_t r_shadows_throwdistance;
4411 extern cvar_t r_shadows_throwdirection;
4412 void R_DrawModelShadows(void)
4415 float relativethrowdistance;
4416 entity_render_t *ent;
4417 vec3_t relativelightorigin;
4418 vec3_t relativelightdirection;
4419 vec3_t relativeshadowmins, relativeshadowmaxs;
4420 vec3_t tmp, shadowdir;
4422 if (!r_drawentities.integer || !gl_stencil)
4426 R_ResetViewRendering3D();
4427 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4428 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4429 R_Shadow_RenderMode_Begin();
4430 R_Shadow_RenderMode_ActiveLight(NULL);
4431 r_shadow_lightscissor[0] = r_refdef.view.x;
4432 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4433 r_shadow_lightscissor[2] = r_refdef.view.width;
4434 r_shadow_lightscissor[3] = r_refdef.view.height;
4435 R_Shadow_RenderMode_StencilShadowVolumes(false);
4438 if (r_shadows.integer == 2)
4440 Math_atov(r_shadows_throwdirection.string, shadowdir);
4441 VectorNormalize(shadowdir);
4444 R_Shadow_ClearStencil();
4446 for (i = 0;i < r_refdef.scene.numentities;i++)
4448 ent = r_refdef.scene.entities[i];
4450 // cast shadows from anything of the map (submodels are optional)
4451 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4453 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4454 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4455 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4456 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4457 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4460 if(ent->entitynumber != 0)
4462 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4463 int entnum, entnum2, recursion;
4464 entnum = entnum2 = ent->entitynumber;
4465 for(recursion = 32; recursion > 0; --recursion)
4467 entnum2 = cl.entities[entnum].state_current.tagentity;
4468 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4473 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4475 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4476 // transform into modelspace of OUR entity
4477 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4478 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4481 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4484 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4487 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4488 RSurf_ActiveModelEntity(ent, false, false);
4489 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4490 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4494 // not really the right mode, but this will disable any silly stencil features
4495 R_Shadow_RenderMode_End();
4497 // set up ortho view for rendering this pass
4498 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4499 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4500 //GL_ScissorTest(true);
4501 //R_Mesh_Matrix(&identitymatrix);
4502 //R_Mesh_ResetTextureState();
4503 R_ResetViewRendering2D();
4504 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4505 R_Mesh_ColorPointer(NULL, 0, 0);
4506 R_SetupGenericShader(false);
4508 // set up a darkening blend on shadowed areas
4509 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4510 //GL_DepthRange(0, 1);
4511 //GL_DepthTest(false);
4512 //GL_DepthMask(false);
4513 //GL_PolygonOffset(0, 0);CHECKGLERROR
4514 GL_Color(0, 0, 0, r_shadows_darken.value);
4515 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4516 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4517 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4518 qglStencilMask(~0);CHECKGLERROR
4519 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4520 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4522 // apply the blend to the shadowed areas
4523 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4525 // restore the viewport
4526 R_SetViewport(&r_refdef.view.viewport);
4528 // restore other state to normal
4529 //R_Shadow_RenderMode_End();
4532 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4535 vec3_t centerorigin;
4536 // if it's too close, skip it
4537 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4539 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4542 if (usequery && r_numqueries + 2 <= r_maxqueries)
4544 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4545 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4546 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4549 // 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
4550 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4551 qglDepthFunc(GL_ALWAYS);
4552 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);
4553 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4554 qglDepthFunc(GL_LEQUAL);
4555 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4556 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);
4557 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4560 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4563 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4566 GLint allpixels = 0, visiblepixels = 0;
4567 // now we have to check the query result
4568 if (rtlight->corona_queryindex_visiblepixels)
4571 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4572 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4574 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4575 if (visiblepixels < 1 || allpixels < 1)
4577 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4578 cscale *= rtlight->corona_visibility;
4582 // FIXME: these traces should scan all render entities instead of cl.world
4583 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4586 VectorScale(rtlight->currentcolor, cscale, color);
4587 if (VectorLength(color) > (1.0f / 256.0f))
4589 qboolean negated = (color[0] + color[1] + color[2] < 0) && gl_support_ext_blend_subtract;
4592 VectorNegate(color, color);
4593 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4595 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);
4597 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4601 void R_DrawCoronas(void)
4609 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4611 if (r_waterstate.renderingscene)
4613 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4614 R_Mesh_Matrix(&identitymatrix);
4616 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4618 // check occlusion of coronas
4619 // use GL_ARB_occlusion_query if available
4620 // otherwise use raytraces
4622 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4625 GL_ColorMask(0,0,0,0);
4626 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4627 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4630 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4631 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4633 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4637 for (lightindex = 0;lightindex < range;lightindex++)
4639 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4642 rtlight = &light->rtlight;
4643 rtlight->corona_visibility = 0;
4644 rtlight->corona_queryindex_visiblepixels = 0;
4645 rtlight->corona_queryindex_allpixels = 0;
4646 if (!(rtlight->flags & flag))
4648 if (rtlight->corona <= 0)
4650 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4652 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4654 for (i = 0;i < r_refdef.scene.numlights;i++)
4656 rtlight = r_refdef.scene.lights[i];
4657 rtlight->corona_visibility = 0;
4658 rtlight->corona_queryindex_visiblepixels = 0;
4659 rtlight->corona_queryindex_allpixels = 0;
4660 if (!(rtlight->flags & flag))
4662 if (rtlight->corona <= 0)
4664 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4667 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4669 // now draw the coronas using the query data for intensity info
4670 for (lightindex = 0;lightindex < range;lightindex++)
4672 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4675 rtlight = &light->rtlight;
4676 if (rtlight->corona_visibility <= 0)
4678 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4680 for (i = 0;i < r_refdef.scene.numlights;i++)
4682 rtlight = r_refdef.scene.lights[i];
4683 if (rtlight->corona_visibility <= 0)
4685 if (gl_flashblend.integer)
4686 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4688 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4694 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4695 typedef struct suffixinfo_s
4698 qboolean flipx, flipy, flipdiagonal;
4701 static suffixinfo_t suffix[3][6] =
4704 {"px", false, false, false},
4705 {"nx", false, false, false},
4706 {"py", false, false, false},
4707 {"ny", false, false, false},
4708 {"pz", false, false, false},
4709 {"nz", false, false, false}
4712 {"posx", false, false, false},
4713 {"negx", false, false, false},
4714 {"posy", false, false, false},
4715 {"negy", false, false, false},
4716 {"posz", false, false, false},
4717 {"negz", false, false, false}
4720 {"rt", true, false, true},
4721 {"lf", false, true, true},
4722 {"ft", true, true, false},
4723 {"bk", false, false, false},
4724 {"up", true, false, true},
4725 {"dn", true, false, true}
4729 static int componentorder[4] = {0, 1, 2, 3};
4731 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4733 int i, j, cubemapsize;
4734 unsigned char *cubemappixels, *image_buffer;
4735 rtexture_t *cubemaptexture;
4737 // must start 0 so the first loadimagepixels has no requested width/height
4739 cubemappixels = NULL;
4740 cubemaptexture = NULL;
4741 // keep trying different suffix groups (posx, px, rt) until one loads
4742 for (j = 0;j < 3 && !cubemappixels;j++)
4744 // load the 6 images in the suffix group
4745 for (i = 0;i < 6;i++)
4747 // generate an image name based on the base and and suffix
4748 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4750 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4752 // an image loaded, make sure width and height are equal
4753 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4755 // if this is the first image to load successfully, allocate the cubemap memory
4756 if (!cubemappixels && image_width >= 1)
4758 cubemapsize = image_width;
4759 // note this clears to black, so unavailable sides are black
4760 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4762 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4764 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);
4767 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4769 Mem_Free(image_buffer);
4773 // if a cubemap loaded, upload it
4776 if (developer_loading.integer)
4777 Con_Printf("loading cubemap \"%s\"\n", basename);
4779 if (!r_shadow_filters_texturepool)
4780 r_shadow_filters_texturepool = R_AllocTexturePool();
4781 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4782 Mem_Free(cubemappixels);
4786 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4787 if (developer_loading.integer)
4789 Con_Printf("(tried tried images ");
4790 for (j = 0;j < 3;j++)
4791 for (i = 0;i < 6;i++)
4792 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4793 Con_Print(" and was unable to find any of them).\n");
4796 return cubemaptexture;
4799 rtexture_t *R_Shadow_Cubemap(const char *basename)
4802 for (i = 0;i < numcubemaps;i++)
4803 if (!strcasecmp(cubemaps[i].basename, basename))
4804 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4805 if (i >= MAX_CUBEMAPS)
4806 return r_texture_whitecube;
4808 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4809 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4810 return cubemaps[i].texture;
4813 void R_Shadow_FreeCubemaps(void)
4816 for (i = 0;i < numcubemaps;i++)
4818 if (developer_loading.integer)
4819 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4820 if (cubemaps[i].texture)
4821 R_FreeTexture(cubemaps[i].texture);
4825 R_FreeTexturePool(&r_shadow_filters_texturepool);
4828 dlight_t *R_Shadow_NewWorldLight(void)
4830 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4833 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)
4836 // validate parameters
4837 if (style < 0 || style >= MAX_LIGHTSTYLES)
4839 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4845 // copy to light properties
4846 VectorCopy(origin, light->origin);
4847 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4848 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4849 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4851 light->color[0] = max(color[0], 0);
4852 light->color[1] = max(color[1], 0);
4853 light->color[2] = max(color[2], 0);
4855 light->color[0] = color[0];
4856 light->color[1] = color[1];
4857 light->color[2] = color[2];
4858 light->radius = max(radius, 0);
4859 light->style = style;
4860 light->shadow = shadowenable;
4861 light->corona = corona;
4862 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4863 light->coronasizescale = coronasizescale;
4864 light->ambientscale = ambientscale;
4865 light->diffusescale = diffusescale;
4866 light->specularscale = specularscale;
4867 light->flags = flags;
4869 // update renderable light data
4870 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4871 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);
4874 void R_Shadow_FreeWorldLight(dlight_t *light)
4876 if (r_shadow_selectedlight == light)
4877 r_shadow_selectedlight = NULL;
4878 R_RTLight_Uncompile(&light->rtlight);
4879 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4882 void R_Shadow_ClearWorldLights(void)
4886 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4887 for (lightindex = 0;lightindex < range;lightindex++)
4889 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4891 R_Shadow_FreeWorldLight(light);
4893 r_shadow_selectedlight = NULL;
4894 R_Shadow_FreeCubemaps();
4897 void R_Shadow_SelectLight(dlight_t *light)
4899 if (r_shadow_selectedlight)
4900 r_shadow_selectedlight->selected = false;
4901 r_shadow_selectedlight = light;
4902 if (r_shadow_selectedlight)
4903 r_shadow_selectedlight->selected = true;
4906 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4908 // this is never batched (there can be only one)
4909 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);
4912 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4919 // this is never batched (due to the ent parameter changing every time)
4920 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4921 const dlight_t *light = (dlight_t *)ent;
4924 VectorScale(light->color, intensity, spritecolor);
4925 if (VectorLength(spritecolor) < 0.1732f)
4926 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4927 if (VectorLength(spritecolor) > 1.0f)
4928 VectorNormalize(spritecolor);
4930 // draw light sprite
4931 if (light->cubemapname[0] && !light->shadow)
4932 pic = r_editlights_sprcubemapnoshadowlight;
4933 else if (light->cubemapname[0])
4934 pic = r_editlights_sprcubemaplight;
4935 else if (!light->shadow)
4936 pic = r_editlights_sprnoshadowlight;
4938 pic = r_editlights_sprlight;
4939 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);
4940 // draw selection sprite if light is selected
4941 if (light->selected)
4942 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);
4943 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4946 void R_Shadow_DrawLightSprites(void)
4950 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4951 for (lightindex = 0;lightindex < range;lightindex++)
4953 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4955 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4957 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4960 void R_Shadow_SelectLightInView(void)
4962 float bestrating, rating, temp[3];
4966 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4969 for (lightindex = 0;lightindex < range;lightindex++)
4971 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4974 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4975 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4978 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4979 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4981 bestrating = rating;
4986 R_Shadow_SelectLight(best);
4989 void R_Shadow_LoadWorldLights(void)
4991 int n, a, style, shadow, flags;
4992 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4993 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4994 if (cl.worldmodel == NULL)
4996 Con_Print("No map loaded.\n");
4999 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5000 strlcat (name, ".rtlights", sizeof (name));
5001 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5011 for (;COM_Parse(t, true) && strcmp(
5012 if (COM_Parse(t, true))
5014 if (com_token[0] == '!')
5017 origin[0] = atof(com_token+1);
5020 origin[0] = atof(com_token);
5025 while (*s && *s != '\n' && *s != '\r')
5031 // check for modifier flags
5038 #if _MSC_VER >= 1400
5039 #define sscanf sscanf_s
5041 cubemapname[sizeof(cubemapname)-1] = 0;
5042 #if MAX_QPATH != 128
5043 #error update this code if MAX_QPATH changes
5045 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
5046 #if _MSC_VER >= 1400
5047 , sizeof(cubemapname)
5049 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5052 flags = LIGHTFLAG_REALTIMEMODE;
5060 coronasizescale = 0.25f;
5062 VectorClear(angles);
5065 if (a < 9 || !strcmp(cubemapname, "\"\""))
5067 // remove quotes on cubemapname
5068 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5071 namelen = strlen(cubemapname) - 2;
5072 memmove(cubemapname, cubemapname + 1, namelen);
5073 cubemapname[namelen] = '\0';
5077 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);
5080 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5088 Con_Printf("invalid rtlights file \"%s\"\n", name);
5089 Mem_Free(lightsstring);
5093 void R_Shadow_SaveWorldLights(void)
5097 size_t bufchars, bufmaxchars;
5099 char name[MAX_QPATH];
5100 char line[MAX_INPUTLINE];
5101 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5102 // I hate lines which are 3 times my screen size :( --blub
5105 if (cl.worldmodel == NULL)
5107 Con_Print("No map loaded.\n");
5110 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5111 strlcat (name, ".rtlights", sizeof (name));
5112 bufchars = bufmaxchars = 0;
5114 for (lightindex = 0;lightindex < range;lightindex++)
5116 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5119 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5120 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);
5121 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5122 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]);
5124 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);
5125 if (bufchars + strlen(line) > bufmaxchars)
5127 bufmaxchars = bufchars + strlen(line) + 2048;
5129 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5133 memcpy(buf, oldbuf, bufchars);
5139 memcpy(buf + bufchars, line, strlen(line));
5140 bufchars += strlen(line);
5144 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5149 void R_Shadow_LoadLightsFile(void)
5152 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5153 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5154 if (cl.worldmodel == NULL)
5156 Con_Print("No map loaded.\n");
5159 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5160 strlcat (name, ".lights", sizeof (name));
5161 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5169 while (*s && *s != '\n' && *s != '\r')
5175 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);
5179 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);
5182 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5183 radius = bound(15, radius, 4096);
5184 VectorScale(color, (2.0f / (8388608.0f)), color);
5185 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5193 Con_Printf("invalid lights file \"%s\"\n", name);
5194 Mem_Free(lightsstring);
5198 // tyrlite/hmap2 light types in the delay field
5199 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5201 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5203 int entnum, style, islight, skin, pflags, effects, type, n;
5206 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5207 char key[256], value[MAX_INPUTLINE];
5209 if (cl.worldmodel == NULL)
5211 Con_Print("No map loaded.\n");
5214 // try to load a .ent file first
5215 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5216 strlcat (key, ".ent", sizeof (key));
5217 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5218 // and if that is not found, fall back to the bsp file entity string
5220 data = cl.worldmodel->brush.entities;
5223 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5225 type = LIGHTTYPE_MINUSX;
5226 origin[0] = origin[1] = origin[2] = 0;
5227 originhack[0] = originhack[1] = originhack[2] = 0;
5228 angles[0] = angles[1] = angles[2] = 0;
5229 color[0] = color[1] = color[2] = 1;
5230 light[0] = light[1] = light[2] = 1;light[3] = 300;
5231 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5241 if (!COM_ParseToken_Simple(&data, false, false))
5243 if (com_token[0] == '}')
5244 break; // end of entity
5245 if (com_token[0] == '_')
5246 strlcpy(key, com_token + 1, sizeof(key));
5248 strlcpy(key, com_token, sizeof(key));
5249 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5250 key[strlen(key)-1] = 0;
5251 if (!COM_ParseToken_Simple(&data, false, false))
5253 strlcpy(value, com_token, sizeof(value));
5255 // now that we have the key pair worked out...
5256 if (!strcmp("light", key))
5258 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5262 light[0] = vec[0] * (1.0f / 256.0f);
5263 light[1] = vec[0] * (1.0f / 256.0f);
5264 light[2] = vec[0] * (1.0f / 256.0f);
5270 light[0] = vec[0] * (1.0f / 255.0f);
5271 light[1] = vec[1] * (1.0f / 255.0f);
5272 light[2] = vec[2] * (1.0f / 255.0f);
5276 else if (!strcmp("delay", key))
5278 else if (!strcmp("origin", key))
5279 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5280 else if (!strcmp("angle", key))
5281 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5282 else if (!strcmp("angles", key))
5283 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5284 else if (!strcmp("color", key))
5285 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5286 else if (!strcmp("wait", key))
5287 fadescale = atof(value);
5288 else if (!strcmp("classname", key))
5290 if (!strncmp(value, "light", 5))
5293 if (!strcmp(value, "light_fluoro"))
5298 overridecolor[0] = 1;
5299 overridecolor[1] = 1;
5300 overridecolor[2] = 1;
5302 if (!strcmp(value, "light_fluorospark"))
5307 overridecolor[0] = 1;
5308 overridecolor[1] = 1;
5309 overridecolor[2] = 1;
5311 if (!strcmp(value, "light_globe"))
5316 overridecolor[0] = 1;
5317 overridecolor[1] = 0.8;
5318 overridecolor[2] = 0.4;
5320 if (!strcmp(value, "light_flame_large_yellow"))
5325 overridecolor[0] = 1;
5326 overridecolor[1] = 0.5;
5327 overridecolor[2] = 0.1;
5329 if (!strcmp(value, "light_flame_small_yellow"))
5334 overridecolor[0] = 1;
5335 overridecolor[1] = 0.5;
5336 overridecolor[2] = 0.1;
5338 if (!strcmp(value, "light_torch_small_white"))
5343 overridecolor[0] = 1;
5344 overridecolor[1] = 0.5;
5345 overridecolor[2] = 0.1;
5347 if (!strcmp(value, "light_torch_small_walltorch"))
5352 overridecolor[0] = 1;
5353 overridecolor[1] = 0.5;
5354 overridecolor[2] = 0.1;
5358 else if (!strcmp("style", key))
5359 style = atoi(value);
5360 else if (!strcmp("skin", key))
5361 skin = (int)atof(value);
5362 else if (!strcmp("pflags", key))
5363 pflags = (int)atof(value);
5364 else if (!strcmp("effects", key))
5365 effects = (int)atof(value);
5366 else if (cl.worldmodel->type == mod_brushq3)
5368 if (!strcmp("scale", key))
5369 lightscale = atof(value);
5370 if (!strcmp("fade", key))
5371 fadescale = atof(value);
5376 if (lightscale <= 0)
5380 if (color[0] == color[1] && color[0] == color[2])
5382 color[0] *= overridecolor[0];
5383 color[1] *= overridecolor[1];
5384 color[2] *= overridecolor[2];
5386 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5387 color[0] = color[0] * light[0];
5388 color[1] = color[1] * light[1];
5389 color[2] = color[2] * light[2];
5392 case LIGHTTYPE_MINUSX:
5394 case LIGHTTYPE_RECIPX:
5396 VectorScale(color, (1.0f / 16.0f), color);
5398 case LIGHTTYPE_RECIPXX:
5400 VectorScale(color, (1.0f / 16.0f), color);
5403 case LIGHTTYPE_NONE:
5407 case LIGHTTYPE_MINUSXX:
5410 VectorAdd(origin, originhack, origin);
5412 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);
5415 Mem_Free(entfiledata);
5419 void R_Shadow_SetCursorLocationForView(void)
5422 vec3_t dest, endpos;
5424 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5425 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5426 if (trace.fraction < 1)
5428 dist = trace.fraction * r_editlights_cursordistance.value;
5429 push = r_editlights_cursorpushback.value;
5433 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5434 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5438 VectorClear( endpos );
5440 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5441 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5442 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5445 void R_Shadow_UpdateWorldLightSelection(void)
5447 if (r_editlights.integer)
5449 R_Shadow_SetCursorLocationForView();
5450 R_Shadow_SelectLightInView();
5453 R_Shadow_SelectLight(NULL);
5456 void R_Shadow_EditLights_Clear_f(void)
5458 R_Shadow_ClearWorldLights();
5461 void R_Shadow_EditLights_Reload_f(void)
5465 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5466 R_Shadow_ClearWorldLights();
5467 R_Shadow_LoadWorldLights();
5468 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5470 R_Shadow_LoadLightsFile();
5471 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5472 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5476 void R_Shadow_EditLights_Save_f(void)
5480 R_Shadow_SaveWorldLights();
5483 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5485 R_Shadow_ClearWorldLights();
5486 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5489 void R_Shadow_EditLights_ImportLightsFile_f(void)
5491 R_Shadow_ClearWorldLights();
5492 R_Shadow_LoadLightsFile();
5495 void R_Shadow_EditLights_Spawn_f(void)
5498 if (!r_editlights.integer)
5500 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5503 if (Cmd_Argc() != 1)
5505 Con_Print("r_editlights_spawn does not take parameters\n");
5508 color[0] = color[1] = color[2] = 1;
5509 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5512 void R_Shadow_EditLights_Edit_f(void)
5514 vec3_t origin, angles, color;
5515 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5516 int style, shadows, flags, normalmode, realtimemode;
5517 char cubemapname[MAX_INPUTLINE];
5518 if (!r_editlights.integer)
5520 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5523 if (!r_shadow_selectedlight)
5525 Con_Print("No selected light.\n");
5528 VectorCopy(r_shadow_selectedlight->origin, origin);
5529 VectorCopy(r_shadow_selectedlight->angles, angles);
5530 VectorCopy(r_shadow_selectedlight->color, color);
5531 radius = r_shadow_selectedlight->radius;
5532 style = r_shadow_selectedlight->style;
5533 if (r_shadow_selectedlight->cubemapname)
5534 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5537 shadows = r_shadow_selectedlight->shadow;
5538 corona = r_shadow_selectedlight->corona;
5539 coronasizescale = r_shadow_selectedlight->coronasizescale;
5540 ambientscale = r_shadow_selectedlight->ambientscale;
5541 diffusescale = r_shadow_selectedlight->diffusescale;
5542 specularscale = r_shadow_selectedlight->specularscale;
5543 flags = r_shadow_selectedlight->flags;
5544 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5545 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5546 if (!strcmp(Cmd_Argv(1), "origin"))
5548 if (Cmd_Argc() != 5)
5550 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5553 origin[0] = atof(Cmd_Argv(2));
5554 origin[1] = atof(Cmd_Argv(3));
5555 origin[2] = atof(Cmd_Argv(4));
5557 else if (!strcmp(Cmd_Argv(1), "originx"))
5559 if (Cmd_Argc() != 3)
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 origin[0] = atof(Cmd_Argv(2));
5566 else if (!strcmp(Cmd_Argv(1), "originy"))
5568 if (Cmd_Argc() != 3)
5570 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5573 origin[1] = atof(Cmd_Argv(2));
5575 else if (!strcmp(Cmd_Argv(1), "originz"))
5577 if (Cmd_Argc() != 3)
5579 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5582 origin[2] = atof(Cmd_Argv(2));
5584 else if (!strcmp(Cmd_Argv(1), "move"))
5586 if (Cmd_Argc() != 5)
5588 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5591 origin[0] += atof(Cmd_Argv(2));
5592 origin[1] += atof(Cmd_Argv(3));
5593 origin[2] += atof(Cmd_Argv(4));
5595 else if (!strcmp(Cmd_Argv(1), "movex"))
5597 if (Cmd_Argc() != 3)
5599 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5602 origin[0] += atof(Cmd_Argv(2));
5604 else if (!strcmp(Cmd_Argv(1), "movey"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 origin[1] += atof(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "movez"))
5615 if (Cmd_Argc() != 3)
5617 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5620 origin[2] += atof(Cmd_Argv(2));
5622 else if (!strcmp(Cmd_Argv(1), "angles"))
5624 if (Cmd_Argc() != 5)
5626 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5629 angles[0] = atof(Cmd_Argv(2));
5630 angles[1] = atof(Cmd_Argv(3));
5631 angles[2] = atof(Cmd_Argv(4));
5633 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5635 if (Cmd_Argc() != 3)
5637 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5640 angles[0] = atof(Cmd_Argv(2));
5642 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5644 if (Cmd_Argc() != 3)
5646 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5649 angles[1] = atof(Cmd_Argv(2));
5651 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5653 if (Cmd_Argc() != 3)
5655 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5658 angles[2] = atof(Cmd_Argv(2));
5660 else if (!strcmp(Cmd_Argv(1), "color"))
5662 if (Cmd_Argc() != 5)
5664 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5667 color[0] = atof(Cmd_Argv(2));
5668 color[1] = atof(Cmd_Argv(3));
5669 color[2] = atof(Cmd_Argv(4));
5671 else if (!strcmp(Cmd_Argv(1), "radius"))
5673 if (Cmd_Argc() != 3)
5675 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5678 radius = atof(Cmd_Argv(2));
5680 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5682 if (Cmd_Argc() == 3)
5684 double scale = atof(Cmd_Argv(2));
5691 if (Cmd_Argc() != 5)
5693 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5696 color[0] *= atof(Cmd_Argv(2));
5697 color[1] *= atof(Cmd_Argv(3));
5698 color[2] *= atof(Cmd_Argv(4));
5701 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5703 if (Cmd_Argc() != 3)
5705 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5708 radius *= atof(Cmd_Argv(2));
5710 else if (!strcmp(Cmd_Argv(1), "style"))
5712 if (Cmd_Argc() != 3)
5714 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5717 style = atoi(Cmd_Argv(2));
5719 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5723 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5726 if (Cmd_Argc() == 3)
5727 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5731 else if (!strcmp(Cmd_Argv(1), "shadows"))
5733 if (Cmd_Argc() != 3)
5735 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5738 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5740 else if (!strcmp(Cmd_Argv(1), "corona"))
5742 if (Cmd_Argc() != 3)
5744 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5747 corona = atof(Cmd_Argv(2));
5749 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5751 if (Cmd_Argc() != 3)
5753 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5756 coronasizescale = atof(Cmd_Argv(2));
5758 else if (!strcmp(Cmd_Argv(1), "ambient"))
5760 if (Cmd_Argc() != 3)
5762 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5765 ambientscale = atof(Cmd_Argv(2));
5767 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5769 if (Cmd_Argc() != 3)
5771 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5774 diffusescale = atof(Cmd_Argv(2));
5776 else if (!strcmp(Cmd_Argv(1), "specular"))
5778 if (Cmd_Argc() != 3)
5780 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5783 specularscale = atof(Cmd_Argv(2));
5785 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5787 if (Cmd_Argc() != 3)
5789 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5792 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5794 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5796 if (Cmd_Argc() != 3)
5798 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5801 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5805 Con_Print("usage: r_editlights_edit [property] [value]\n");
5806 Con_Print("Selected light's properties:\n");
5807 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5808 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5809 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5810 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5811 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5812 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5813 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5814 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5815 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5816 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5817 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5818 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5819 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5820 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5823 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5824 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5827 void R_Shadow_EditLights_EditAll_f(void)
5833 if (!r_editlights.integer)
5835 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5839 // EditLights doesn't seem to have a "remove" command or something so:
5840 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5841 for (lightindex = 0;lightindex < range;lightindex++)
5843 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5846 R_Shadow_SelectLight(light);
5847 R_Shadow_EditLights_Edit_f();
5851 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5853 int lightnumber, lightcount;
5854 size_t lightindex, range;
5858 if (!r_editlights.integer)
5860 x = vid_conwidth.value - 240;
5862 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5865 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5866 for (lightindex = 0;lightindex < range;lightindex++)
5868 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5871 if (light == r_shadow_selectedlight)
5872 lightnumber = lightindex;
5875 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;
5876 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;
5878 if (r_shadow_selectedlight == NULL)
5880 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;
5881 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;
5882 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;
5883 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;
5884 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;
5885 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;
5886 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;
5887 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;
5888 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;
5889 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;
5890 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;
5891 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;
5892 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;
5893 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;
5894 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;
5897 void R_Shadow_EditLights_ToggleShadow_f(void)
5899 if (!r_editlights.integer)
5901 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5904 if (!r_shadow_selectedlight)
5906 Con_Print("No selected light.\n");
5909 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);
5912 void R_Shadow_EditLights_ToggleCorona_f(void)
5914 if (!r_editlights.integer)
5916 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5919 if (!r_shadow_selectedlight)
5921 Con_Print("No selected light.\n");
5924 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);
5927 void R_Shadow_EditLights_Remove_f(void)
5929 if (!r_editlights.integer)
5931 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5934 if (!r_shadow_selectedlight)
5936 Con_Print("No selected light.\n");
5939 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5940 r_shadow_selectedlight = NULL;
5943 void R_Shadow_EditLights_Help_f(void)
5946 "Documentation on r_editlights system:\n"
5948 "r_editlights : enable/disable editing mode\n"
5949 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5950 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5951 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5952 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5953 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5955 "r_editlights_help : this help\n"
5956 "r_editlights_clear : remove all lights\n"
5957 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5958 "r_editlights_save : save to .rtlights file\n"
5959 "r_editlights_spawn : create a light with default settings\n"
5960 "r_editlights_edit command : edit selected light - more documentation below\n"
5961 "r_editlights_remove : remove selected light\n"
5962 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5963 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5964 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5966 "origin x y z : set light location\n"
5967 "originx x: set x component of light location\n"
5968 "originy y: set y component of light location\n"
5969 "originz z: set z component of light location\n"
5970 "move x y z : adjust light location\n"
5971 "movex x: adjust x component of light location\n"
5972 "movey y: adjust y component of light location\n"
5973 "movez z: adjust z component of light location\n"
5974 "angles x y z : set light angles\n"
5975 "anglesx x: set x component of light angles\n"
5976 "anglesy y: set y component of light angles\n"
5977 "anglesz z: set z component of light angles\n"
5978 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5979 "radius radius : set radius (size) of light\n"
5980 "colorscale grey : multiply color of light (1 does nothing)\n"
5981 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5982 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5983 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5984 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5985 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5986 "shadows 1/0 : turn on/off shadows\n"
5987 "corona n : set corona intensity\n"
5988 "coronasize n : set corona size (0-1)\n"
5989 "ambient n : set ambient intensity (0-1)\n"
5990 "diffuse n : set diffuse intensity (0-1)\n"
5991 "specular n : set specular intensity (0-1)\n"
5992 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5993 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5994 "<nothing> : print light properties to console\n"
5998 void R_Shadow_EditLights_CopyInfo_f(void)
6000 if (!r_editlights.integer)
6002 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6005 if (!r_shadow_selectedlight)
6007 Con_Print("No selected light.\n");
6010 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6011 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6012 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6013 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6014 if (r_shadow_selectedlight->cubemapname)
6015 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6017 r_shadow_bufferlight.cubemapname[0] = 0;
6018 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6019 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6020 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6021 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6022 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6023 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6024 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6027 void R_Shadow_EditLights_PasteInfo_f(void)
6029 if (!r_editlights.integer)
6031 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6034 if (!r_shadow_selectedlight)
6036 Con_Print("No selected light.\n");
6039 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);
6042 void R_Shadow_EditLights_Init(void)
6044 Cvar_RegisterVariable(&r_editlights);
6045 Cvar_RegisterVariable(&r_editlights_cursordistance);
6046 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6047 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6048 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6049 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6050 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6051 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6052 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)");
6053 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6054 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6055 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6056 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)");
6057 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6058 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6059 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6060 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6061 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6062 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6063 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)");
6069 =============================================================================
6073 =============================================================================
6076 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6078 VectorClear(diffusecolor);
6079 VectorClear(diffusenormal);
6081 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6083 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6084 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6087 VectorSet(ambientcolor, 1, 1, 1);
6094 for (i = 0;i < r_refdef.scene.numlights;i++)
6096 light = r_refdef.scene.lights[i];
6097 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6098 f = 1 - VectorLength2(v);
6099 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6100 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);