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 skinframe_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 static int numcubemaps;
349 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 #define EDLIGHTSPRSIZE 8
362 skinframe_t *r_editlights_sprcursor;
363 skinframe_t *r_editlights_sprlight;
364 skinframe_t *r_editlights_sprnoshadowlight;
365 skinframe_t *r_editlights_sprcubemaplight;
366 skinframe_t *r_editlights_sprcubemapnoshadowlight;
367 skinframe_t *r_editlights_sprselection;
369 void R_Shadow_SetShadowMode(void)
371 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
372 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
373 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
374 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
375 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
376 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
377 r_shadow_shadowmaplod = -1;
378 r_shadow_shadowmapsize = 0;
379 r_shadow_shadowmapsampler = false;
380 r_shadow_shadowmappcf = 0;
381 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
382 if(r_shadow_shadowmapping.integer && r_glsl.integer && vid.support.arb_fragment_shader && vid.support.ext_framebuffer_object)
384 if(r_shadow_shadowmapfilterquality < 0)
386 if(strstr(gl_vendor, "NVIDIA"))
388 r_shadow_shadowmapsampler = vid.support.arb_shadow;
389 r_shadow_shadowmappcf = 1;
391 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
392 r_shadow_shadowmappcf = 1;
393 else if(strstr(gl_vendor, "ATI"))
394 r_shadow_shadowmappcf = 1;
396 r_shadow_shadowmapsampler = vid.support.arb_shadow;
400 switch (r_shadow_shadowmapfilterquality)
403 r_shadow_shadowmapsampler = vid.support.arb_shadow;
406 r_shadow_shadowmapsampler = vid.support.arb_shadow;
407 r_shadow_shadowmappcf = 1;
410 r_shadow_shadowmappcf = 1;
413 r_shadow_shadowmappcf = 2;
417 switch (r_shadow_shadowmaptexturetype)
420 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
423 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
426 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
429 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
431 else if(vid.support.arb_texture_rectangle)
432 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
440 void R_Shadow_FreeShadowMaps(void)
444 R_Shadow_SetShadowMode();
446 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
451 if (r_shadow_fborectangle)
452 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
453 r_shadow_fborectangle = 0;
456 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
458 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
459 if (r_shadow_fbocubeside[i])
460 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
461 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
463 if (r_shadow_shadowmaprectangletexture)
464 R_FreeTexture(r_shadow_shadowmaprectangletexture);
465 r_shadow_shadowmaprectangletexture = NULL;
467 if (r_shadow_shadowmap2dtexture)
468 R_FreeTexture(r_shadow_shadowmap2dtexture);
469 r_shadow_shadowmap2dtexture = NULL;
471 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
472 if (r_shadow_shadowmapcubetexture[i])
473 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
474 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
476 if (r_shadow_shadowmapvsdcttexture)
477 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
478 r_shadow_shadowmapvsdcttexture = NULL;
483 void r_shadow_start(void)
485 // allocate vertex processing arrays
487 r_shadow_attenuationgradienttexture = NULL;
488 r_shadow_attenuation2dtexture = NULL;
489 r_shadow_attenuation3dtexture = NULL;
490 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
491 r_shadow_shadowmaprectangletexture = NULL;
492 r_shadow_shadowmap2dtexture = NULL;
493 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
494 r_shadow_shadowmapvsdcttexture = NULL;
495 r_shadow_shadowmapmaxsize = 0;
496 r_shadow_shadowmapsize = 0;
497 r_shadow_shadowmaplod = 0;
498 r_shadow_shadowmapfilterquality = -1;
499 r_shadow_shadowmaptexturetype = -1;
500 r_shadow_shadowmapdepthbits = 0;
501 r_shadow_shadowmapvsdct = false;
502 r_shadow_shadowmapsampler = false;
503 r_shadow_shadowmappcf = 0;
504 r_shadow_fborectangle = 0;
506 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
508 R_Shadow_FreeShadowMaps();
510 r_shadow_texturepool = NULL;
511 r_shadow_filters_texturepool = NULL;
512 R_Shadow_ValidateCvars();
513 R_Shadow_MakeTextures();
514 maxshadowtriangles = 0;
515 shadowelements = NULL;
516 maxshadowvertices = 0;
517 shadowvertex3f = NULL;
525 shadowmarklist = NULL;
530 shadowsideslist = NULL;
531 r_shadow_buffer_numleafpvsbytes = 0;
532 r_shadow_buffer_visitingleafpvs = NULL;
533 r_shadow_buffer_leafpvs = NULL;
534 r_shadow_buffer_leaflist = NULL;
535 r_shadow_buffer_numsurfacepvsbytes = 0;
536 r_shadow_buffer_surfacepvs = NULL;
537 r_shadow_buffer_surfacelist = NULL;
538 r_shadow_buffer_surfacesides = NULL;
539 r_shadow_buffer_numshadowtrispvsbytes = 0;
540 r_shadow_buffer_shadowtrispvs = NULL;
541 r_shadow_buffer_numlighttrispvsbytes = 0;
542 r_shadow_buffer_lighttrispvs = NULL;
545 void r_shadow_shutdown(void)
548 R_Shadow_UncompileWorldLights();
550 R_Shadow_FreeShadowMaps();
554 r_shadow_attenuationgradienttexture = NULL;
555 r_shadow_attenuation2dtexture = NULL;
556 r_shadow_attenuation3dtexture = NULL;
557 R_FreeTexturePool(&r_shadow_texturepool);
558 R_FreeTexturePool(&r_shadow_filters_texturepool);
559 maxshadowtriangles = 0;
561 Mem_Free(shadowelements);
562 shadowelements = NULL;
564 Mem_Free(shadowvertex3f);
565 shadowvertex3f = NULL;
568 Mem_Free(vertexupdate);
571 Mem_Free(vertexremap);
577 Mem_Free(shadowmark);
580 Mem_Free(shadowmarklist);
581 shadowmarklist = NULL;
586 Mem_Free(shadowsides);
589 Mem_Free(shadowsideslist);
590 shadowsideslist = NULL;
591 r_shadow_buffer_numleafpvsbytes = 0;
592 if (r_shadow_buffer_visitingleafpvs)
593 Mem_Free(r_shadow_buffer_visitingleafpvs);
594 r_shadow_buffer_visitingleafpvs = NULL;
595 if (r_shadow_buffer_leafpvs)
596 Mem_Free(r_shadow_buffer_leafpvs);
597 r_shadow_buffer_leafpvs = NULL;
598 if (r_shadow_buffer_leaflist)
599 Mem_Free(r_shadow_buffer_leaflist);
600 r_shadow_buffer_leaflist = NULL;
601 r_shadow_buffer_numsurfacepvsbytes = 0;
602 if (r_shadow_buffer_surfacepvs)
603 Mem_Free(r_shadow_buffer_surfacepvs);
604 r_shadow_buffer_surfacepvs = NULL;
605 if (r_shadow_buffer_surfacelist)
606 Mem_Free(r_shadow_buffer_surfacelist);
607 r_shadow_buffer_surfacelist = NULL;
608 if (r_shadow_buffer_surfacesides)
609 Mem_Free(r_shadow_buffer_surfacesides);
610 r_shadow_buffer_surfacesides = NULL;
611 r_shadow_buffer_numshadowtrispvsbytes = 0;
612 if (r_shadow_buffer_shadowtrispvs)
613 Mem_Free(r_shadow_buffer_shadowtrispvs);
614 r_shadow_buffer_numlighttrispvsbytes = 0;
615 if (r_shadow_buffer_lighttrispvs)
616 Mem_Free(r_shadow_buffer_lighttrispvs);
619 void r_shadow_newmap(void)
621 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
622 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
623 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
624 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
625 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
626 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
627 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
628 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
629 R_Shadow_EditLights_Reload_f();
632 void R_Shadow_Init(void)
634 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
635 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
636 Cvar_RegisterVariable(&r_shadow_dot3);
637 Cvar_RegisterVariable(&r_shadow_usenormalmap);
638 Cvar_RegisterVariable(&r_shadow_debuglight);
639 Cvar_RegisterVariable(&r_shadow_gloss);
640 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
641 Cvar_RegisterVariable(&r_shadow_glossintensity);
642 Cvar_RegisterVariable(&r_shadow_glossexponent);
643 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
644 Cvar_RegisterVariable(&r_shadow_glossexact);
645 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
646 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
647 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
648 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
649 Cvar_RegisterVariable(&r_shadow_portallight);
650 Cvar_RegisterVariable(&r_shadow_projectdistance);
651 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
653 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
654 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
655 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
656 Cvar_RegisterVariable(&r_shadow_realtime_world);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
663 Cvar_RegisterVariable(&r_shadow_scissor);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
672 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
673 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
678 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
679 Cvar_RegisterVariable(&r_shadow_culltriangles);
680 Cvar_RegisterVariable(&r_shadow_polygonfactor);
681 Cvar_RegisterVariable(&r_shadow_polygonoffset);
682 Cvar_RegisterVariable(&r_shadow_texture3d);
683 Cvar_RegisterVariable(&r_coronas);
684 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
685 Cvar_RegisterVariable(&r_coronas_occlusionquery);
686 Cvar_RegisterVariable(&gl_flashblend);
687 Cvar_RegisterVariable(&gl_ext_separatestencil);
688 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
689 if (gamemode == GAME_TENEBRAE)
691 Cvar_SetValue("r_shadow_gloss", 2);
692 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
694 R_Shadow_EditLights_Init();
695 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
696 maxshadowtriangles = 0;
697 shadowelements = NULL;
698 maxshadowvertices = 0;
699 shadowvertex3f = NULL;
707 shadowmarklist = NULL;
712 shadowsideslist = NULL;
713 r_shadow_buffer_numleafpvsbytes = 0;
714 r_shadow_buffer_visitingleafpvs = NULL;
715 r_shadow_buffer_leafpvs = NULL;
716 r_shadow_buffer_leaflist = NULL;
717 r_shadow_buffer_numsurfacepvsbytes = 0;
718 r_shadow_buffer_surfacepvs = NULL;
719 r_shadow_buffer_surfacelist = NULL;
720 r_shadow_buffer_surfacesides = NULL;
721 r_shadow_buffer_shadowtrispvs = NULL;
722 r_shadow_buffer_lighttrispvs = NULL;
723 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
726 matrix4x4_t matrix_attenuationxyz =
729 {0.5, 0.0, 0.0, 0.5},
730 {0.0, 0.5, 0.0, 0.5},
731 {0.0, 0.0, 0.5, 0.5},
736 matrix4x4_t matrix_attenuationz =
739 {0.0, 0.0, 0.5, 0.5},
740 {0.0, 0.0, 0.0, 0.5},
741 {0.0, 0.0, 0.0, 0.5},
746 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
748 numvertices = ((numvertices + 255) & ~255) * vertscale;
749 numtriangles = ((numtriangles + 255) & ~255) * triscale;
750 // make sure shadowelements is big enough for this volume
751 if (maxshadowtriangles < numtriangles)
753 maxshadowtriangles = numtriangles;
755 Mem_Free(shadowelements);
756 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
758 // make sure shadowvertex3f is big enough for this volume
759 if (maxshadowvertices < numvertices)
761 maxshadowvertices = numvertices;
763 Mem_Free(shadowvertex3f);
764 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
768 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
770 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
771 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
772 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
773 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
774 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
776 if (r_shadow_buffer_visitingleafpvs)
777 Mem_Free(r_shadow_buffer_visitingleafpvs);
778 if (r_shadow_buffer_leafpvs)
779 Mem_Free(r_shadow_buffer_leafpvs);
780 if (r_shadow_buffer_leaflist)
781 Mem_Free(r_shadow_buffer_leaflist);
782 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
783 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
784 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
785 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
787 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
789 if (r_shadow_buffer_surfacepvs)
790 Mem_Free(r_shadow_buffer_surfacepvs);
791 if (r_shadow_buffer_surfacelist)
792 Mem_Free(r_shadow_buffer_surfacelist);
793 if (r_shadow_buffer_surfacesides)
794 Mem_Free(r_shadow_buffer_surfacesides);
795 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
796 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
797 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
798 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
800 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
802 if (r_shadow_buffer_shadowtrispvs)
803 Mem_Free(r_shadow_buffer_shadowtrispvs);
804 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
805 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
807 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
809 if (r_shadow_buffer_lighttrispvs)
810 Mem_Free(r_shadow_buffer_lighttrispvs);
811 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
812 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
816 void R_Shadow_PrepareShadowMark(int numtris)
818 // make sure shadowmark is big enough for this volume
819 if (maxshadowmark < numtris)
821 maxshadowmark = numtris;
823 Mem_Free(shadowmark);
825 Mem_Free(shadowmarklist);
826 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
827 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
831 // if shadowmarkcount wrapped we clear the array and adjust accordingly
832 if (shadowmarkcount == 0)
835 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
840 void R_Shadow_PrepareShadowSides(int numtris)
842 if (maxshadowsides < numtris)
844 maxshadowsides = numtris;
846 Mem_Free(shadowsides);
848 Mem_Free(shadowsideslist);
849 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
850 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
855 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)
858 int outtriangles = 0, outvertices = 0;
861 float ratio, direction[3], projectvector[3];
863 if (projectdirection)
864 VectorScale(projectdirection, projectdistance, projectvector);
866 VectorClear(projectvector);
868 // create the vertices
869 if (projectdirection)
871 for (i = 0;i < numshadowmarktris;i++)
873 element = inelement3i + shadowmarktris[i] * 3;
874 for (j = 0;j < 3;j++)
876 if (vertexupdate[element[j]] != vertexupdatenum)
878 vertexupdate[element[j]] = vertexupdatenum;
879 vertexremap[element[j]] = outvertices;
880 vertex = invertex3f + element[j] * 3;
881 // project one copy of the vertex according to projectvector
882 VectorCopy(vertex, outvertex3f);
883 VectorAdd(vertex, projectvector, (outvertex3f + 3));
892 for (i = 0;i < numshadowmarktris;i++)
894 element = inelement3i + shadowmarktris[i] * 3;
895 for (j = 0;j < 3;j++)
897 if (vertexupdate[element[j]] != vertexupdatenum)
899 vertexupdate[element[j]] = vertexupdatenum;
900 vertexremap[element[j]] = outvertices;
901 vertex = invertex3f + element[j] * 3;
902 // project one copy of the vertex to the sphere radius of the light
903 // (FIXME: would projecting it to the light box be better?)
904 VectorSubtract(vertex, projectorigin, direction);
905 ratio = projectdistance / VectorLength(direction);
906 VectorCopy(vertex, outvertex3f);
907 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
915 if (r_shadow_frontsidecasting.integer)
917 for (i = 0;i < numshadowmarktris;i++)
919 int remappedelement[3];
921 const int *neighbortriangle;
923 markindex = shadowmarktris[i] * 3;
924 element = inelement3i + markindex;
925 neighbortriangle = inneighbor3i + markindex;
926 // output the front and back triangles
927 outelement3i[0] = vertexremap[element[0]];
928 outelement3i[1] = vertexremap[element[1]];
929 outelement3i[2] = vertexremap[element[2]];
930 outelement3i[3] = vertexremap[element[2]] + 1;
931 outelement3i[4] = vertexremap[element[1]] + 1;
932 outelement3i[5] = vertexremap[element[0]] + 1;
936 // output the sides (facing outward from this triangle)
937 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
939 remappedelement[0] = vertexremap[element[0]];
940 remappedelement[1] = vertexremap[element[1]];
941 outelement3i[0] = remappedelement[1];
942 outelement3i[1] = remappedelement[0];
943 outelement3i[2] = remappedelement[0] + 1;
944 outelement3i[3] = remappedelement[1];
945 outelement3i[4] = remappedelement[0] + 1;
946 outelement3i[5] = remappedelement[1] + 1;
951 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
953 remappedelement[1] = vertexremap[element[1]];
954 remappedelement[2] = vertexremap[element[2]];
955 outelement3i[0] = remappedelement[2];
956 outelement3i[1] = remappedelement[1];
957 outelement3i[2] = remappedelement[1] + 1;
958 outelement3i[3] = remappedelement[2];
959 outelement3i[4] = remappedelement[1] + 1;
960 outelement3i[5] = remappedelement[2] + 1;
965 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
967 remappedelement[0] = vertexremap[element[0]];
968 remappedelement[2] = vertexremap[element[2]];
969 outelement3i[0] = remappedelement[0];
970 outelement3i[1] = remappedelement[2];
971 outelement3i[2] = remappedelement[2] + 1;
972 outelement3i[3] = remappedelement[0];
973 outelement3i[4] = remappedelement[2] + 1;
974 outelement3i[5] = remappedelement[0] + 1;
983 for (i = 0;i < numshadowmarktris;i++)
985 int remappedelement[3];
987 const int *neighbortriangle;
989 markindex = shadowmarktris[i] * 3;
990 element = inelement3i + markindex;
991 neighbortriangle = inneighbor3i + markindex;
992 // output the front and back triangles
993 outelement3i[0] = vertexremap[element[2]];
994 outelement3i[1] = vertexremap[element[1]];
995 outelement3i[2] = vertexremap[element[0]];
996 outelement3i[3] = vertexremap[element[0]] + 1;
997 outelement3i[4] = vertexremap[element[1]] + 1;
998 outelement3i[5] = vertexremap[element[2]] + 1;
1002 // output the sides (facing outward from this triangle)
1003 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1005 remappedelement[0] = vertexremap[element[0]];
1006 remappedelement[1] = vertexremap[element[1]];
1007 outelement3i[0] = remappedelement[0];
1008 outelement3i[1] = remappedelement[1];
1009 outelement3i[2] = remappedelement[1] + 1;
1010 outelement3i[3] = remappedelement[0];
1011 outelement3i[4] = remappedelement[1] + 1;
1012 outelement3i[5] = remappedelement[0] + 1;
1017 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1019 remappedelement[1] = vertexremap[element[1]];
1020 remappedelement[2] = vertexremap[element[2]];
1021 outelement3i[0] = remappedelement[1];
1022 outelement3i[1] = remappedelement[2];
1023 outelement3i[2] = remappedelement[2] + 1;
1024 outelement3i[3] = remappedelement[1];
1025 outelement3i[4] = remappedelement[2] + 1;
1026 outelement3i[5] = remappedelement[1] + 1;
1031 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1033 remappedelement[0] = vertexremap[element[0]];
1034 remappedelement[2] = vertexremap[element[2]];
1035 outelement3i[0] = remappedelement[2];
1036 outelement3i[1] = remappedelement[0];
1037 outelement3i[2] = remappedelement[0] + 1;
1038 outelement3i[3] = remappedelement[2];
1039 outelement3i[4] = remappedelement[0] + 1;
1040 outelement3i[5] = remappedelement[2] + 1;
1048 *outnumvertices = outvertices;
1049 return outtriangles;
1052 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)
1055 int outtriangles = 0, outvertices = 0;
1057 const float *vertex;
1058 float ratio, direction[3], projectvector[3];
1061 if (projectdirection)
1062 VectorScale(projectdirection, projectdistance, projectvector);
1064 VectorClear(projectvector);
1066 for (i = 0;i < numshadowmarktris;i++)
1068 int remappedelement[3];
1070 const int *neighbortriangle;
1072 markindex = shadowmarktris[i] * 3;
1073 neighbortriangle = inneighbor3i + markindex;
1074 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1075 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1076 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1077 if (side[0] + side[1] + side[2] == 0)
1081 element = inelement3i + markindex;
1083 // create the vertices
1084 for (j = 0;j < 3;j++)
1086 if (side[j] + side[j+1] == 0)
1089 if (vertexupdate[k] != vertexupdatenum)
1091 vertexupdate[k] = vertexupdatenum;
1092 vertexremap[k] = outvertices;
1093 vertex = invertex3f + k * 3;
1094 VectorCopy(vertex, outvertex3f);
1095 if (projectdirection)
1097 // project one copy of the vertex according to projectvector
1098 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1102 // project one copy of the vertex to the sphere radius of the light
1103 // (FIXME: would projecting it to the light box be better?)
1104 VectorSubtract(vertex, projectorigin, direction);
1105 ratio = projectdistance / VectorLength(direction);
1106 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1113 // output the sides (facing outward from this triangle)
1116 remappedelement[0] = vertexremap[element[0]];
1117 remappedelement[1] = vertexremap[element[1]];
1118 outelement3i[0] = remappedelement[1];
1119 outelement3i[1] = remappedelement[0];
1120 outelement3i[2] = remappedelement[0] + 1;
1121 outelement3i[3] = remappedelement[1];
1122 outelement3i[4] = remappedelement[0] + 1;
1123 outelement3i[5] = remappedelement[1] + 1;
1130 remappedelement[1] = vertexremap[element[1]];
1131 remappedelement[2] = vertexremap[element[2]];
1132 outelement3i[0] = remappedelement[2];
1133 outelement3i[1] = remappedelement[1];
1134 outelement3i[2] = remappedelement[1] + 1;
1135 outelement3i[3] = remappedelement[2];
1136 outelement3i[4] = remappedelement[1] + 1;
1137 outelement3i[5] = remappedelement[2] + 1;
1144 remappedelement[0] = vertexremap[element[0]];
1145 remappedelement[2] = vertexremap[element[2]];
1146 outelement3i[0] = remappedelement[0];
1147 outelement3i[1] = remappedelement[2];
1148 outelement3i[2] = remappedelement[2] + 1;
1149 outelement3i[3] = remappedelement[0];
1150 outelement3i[4] = remappedelement[2] + 1;
1151 outelement3i[5] = remappedelement[0] + 1;
1158 *outnumvertices = outvertices;
1159 return outtriangles;
1162 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)
1168 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1170 tend = firsttriangle + numtris;
1171 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1173 // surface box entirely inside light box, no box cull
1174 if (projectdirection)
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1178 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1179 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1180 shadowmarklist[numshadowmark++] = t;
1185 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1186 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1187 shadowmarklist[numshadowmark++] = t;
1192 // surface box not entirely inside light box, cull each triangle
1193 if (projectdirection)
1195 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1197 v[0] = invertex3f + e[0] * 3;
1198 v[1] = invertex3f + e[1] * 3;
1199 v[2] = invertex3f + e[2] * 3;
1200 TriangleNormal(v[0], v[1], v[2], normal);
1201 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1202 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1203 shadowmarklist[numshadowmark++] = t;
1208 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1210 v[0] = invertex3f + e[0] * 3;
1211 v[1] = invertex3f + e[1] * 3;
1212 v[2] = invertex3f + e[2] * 3;
1213 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1214 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1215 shadowmarklist[numshadowmark++] = t;
1221 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1226 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1228 // check if the shadow volume intersects the near plane
1230 // a ray between the eye and light origin may intersect the caster,
1231 // indicating that the shadow may touch the eye location, however we must
1232 // test the near plane (a polygon), not merely the eye location, so it is
1233 // easiest to enlarge the caster bounding shape slightly for this.
1239 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)
1241 int i, tris, outverts;
1242 if (projectdistance < 0.1)
1244 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1247 if (!numverts || !nummarktris)
1249 // make sure shadowelements is big enough for this volume
1250 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1251 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1253 if (maxvertexupdate < numverts)
1255 maxvertexupdate = numverts;
1257 Mem_Free(vertexupdate);
1259 Mem_Free(vertexremap);
1260 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1261 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1262 vertexupdatenum = 0;
1265 if (vertexupdatenum == 0)
1267 vertexupdatenum = 1;
1268 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1269 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1272 for (i = 0;i < nummarktris;i++)
1273 shadowmark[marktris[i]] = shadowmarkcount;
1275 if (r_shadow_compilingrtlight)
1277 // if we're compiling an rtlight, capture the mesh
1278 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1279 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1280 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1285 // decide which type of shadow to generate and set stencil mode
1286 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1287 // generate the sides or a solid volume, depending on type
1288 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1289 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1291 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1292 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1293 r_refdef.stats.lights_shadowtriangles += tris;
1295 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1296 GL_LockArrays(0, outverts);
1297 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1299 // increment stencil if frontface is infront of depthbuffer
1300 GL_CullFace(r_refdef.view.cullface_front);
1301 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1302 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1303 // decrement stencil if backface is infront of depthbuffer
1304 GL_CullFace(r_refdef.view.cullface_back);
1305 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1307 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1309 // decrement stencil if backface is behind depthbuffer
1310 GL_CullFace(r_refdef.view.cullface_front);
1311 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1312 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1313 // increment stencil if frontface is behind depthbuffer
1314 GL_CullFace(r_refdef.view.cullface_back);
1315 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1317 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1318 GL_LockArrays(0, 0);
1323 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1325 // p1, p2, p3 are in the cubemap's local coordinate system
1326 // bias = border/(size - border)
1329 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1330 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1331 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1332 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1334 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1335 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1336 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1337 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1339 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1340 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1341 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1343 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1344 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1345 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1346 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1348 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1349 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1350 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1351 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1353 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1354 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1355 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1357 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1358 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1359 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1360 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1362 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1363 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1364 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1365 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1367 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1368 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1369 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1374 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1376 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1377 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1380 VectorSubtract(maxs, mins, radius);
1381 VectorScale(radius, 0.5f, radius);
1382 VectorAdd(mins, radius, center);
1383 Matrix4x4_Transform(worldtolight, center, lightcenter);
1384 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1385 VectorSubtract(lightcenter, lightradius, pmin);
1386 VectorAdd(lightcenter, lightradius, pmax);
1388 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1389 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1390 if(ap1 > bias*an1 && ap2 > bias*an2)
1392 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1393 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1394 if(an1 > bias*ap1 && an2 > bias*ap2)
1396 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1397 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1399 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1400 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1401 if(ap1 > bias*an1 && ap2 > bias*an2)
1403 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1404 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1405 if(an1 > bias*ap1 && an2 > bias*ap2)
1407 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1408 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1410 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1411 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1412 if(ap1 > bias*an1 && ap2 > bias*an2)
1414 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1415 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1416 if(an1 > bias*ap1 && an2 > bias*ap2)
1418 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1419 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1424 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1426 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1428 // p is in the cubemap's local coordinate system
1429 // bias = border/(size - border)
1430 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1431 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1432 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1434 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1435 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1436 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1437 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1438 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1439 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1443 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1447 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1448 float scale = (size - 2*border)/size, len;
1449 float bias = border / (float)(size - border), dp, dn, ap, an;
1450 // check if cone enclosing side would cross frustum plane
1451 scale = 2 / (scale*scale + 2);
1452 for (i = 0;i < 5;i++)
1454 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1456 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1457 len = scale*VectorLength2(n);
1458 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1459 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1460 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1462 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1464 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1465 len = scale*VectorLength(n);
1466 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1467 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1468 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1470 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1471 // check if frustum corners/origin cross plane sides
1472 for (i = 0;i < 5;i++)
1474 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1475 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1476 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1477 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1478 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1479 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1480 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1481 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1482 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1483 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1485 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1488 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)
1496 int mask, surfacemask = 0;
1497 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1499 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1500 tend = firsttriangle + numtris;
1501 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1503 // surface box entirely inside light box, no box cull
1504 if (projectdirection)
1506 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1508 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1509 TriangleNormal(v[0], v[1], v[2], normal);
1510 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1512 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1513 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1514 surfacemask |= mask;
1517 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;
1518 shadowsides[numshadowsides] = mask;
1519 shadowsideslist[numshadowsides++] = t;
1526 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1528 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1529 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1531 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1532 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1533 surfacemask |= mask;
1536 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;
1537 shadowsides[numshadowsides] = mask;
1538 shadowsideslist[numshadowsides++] = t;
1546 // surface box not entirely inside light box, cull each triangle
1547 if (projectdirection)
1549 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1551 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1552 TriangleNormal(v[0], v[1], v[2], normal);
1553 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1554 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1556 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1557 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1558 surfacemask |= mask;
1561 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;
1562 shadowsides[numshadowsides] = mask;
1563 shadowsideslist[numshadowsides++] = t;
1570 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1572 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1573 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1574 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1576 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1577 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1578 surfacemask |= mask;
1581 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;
1582 shadowsides[numshadowsides] = mask;
1583 shadowsideslist[numshadowsides++] = t;
1592 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)
1594 int i, j, outtriangles = 0;
1595 int *outelement3i[6];
1596 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1598 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1599 // make sure shadowelements is big enough for this mesh
1600 if (maxshadowtriangles < outtriangles)
1601 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1603 // compute the offset and size of the separate index lists for each cubemap side
1605 for (i = 0;i < 6;i++)
1607 outelement3i[i] = shadowelements + outtriangles * 3;
1608 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1609 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1610 outtriangles += sidetotals[i];
1613 // gather up the (sparse) triangles into separate index lists for each cubemap side
1614 for (i = 0;i < numsidetris;i++)
1616 const int *element = elements + sidetris[i] * 3;
1617 for (j = 0;j < 6;j++)
1619 if (sides[i] & (1 << j))
1621 outelement3i[j][0] = element[0];
1622 outelement3i[j][1] = element[1];
1623 outelement3i[j][2] = element[2];
1624 outelement3i[j] += 3;
1629 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1632 static void R_Shadow_MakeTextures_MakeCorona(void)
1636 unsigned char pixels[32][32][4];
1637 for (y = 0;y < 32;y++)
1639 dy = (y - 15.5f) * (1.0f / 16.0f);
1640 for (x = 0;x < 32;x++)
1642 dx = (x - 15.5f) * (1.0f / 16.0f);
1643 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1644 a = bound(0, a, 255);
1645 pixels[y][x][0] = a;
1646 pixels[y][x][1] = a;
1647 pixels[y][x][2] = a;
1648 pixels[y][x][3] = 255;
1651 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1654 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1656 float dist = sqrt(x*x+y*y+z*z);
1657 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1658 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1659 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1662 static void R_Shadow_MakeTextures(void)
1665 float intensity, dist;
1667 R_Shadow_FreeShadowMaps();
1668 R_FreeTexturePool(&r_shadow_texturepool);
1669 r_shadow_texturepool = R_AllocTexturePool();
1670 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1671 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1672 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1673 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1674 for (x = 0;x <= ATTENTABLESIZE;x++)
1676 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1677 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1678 r_shadow_attentable[x] = bound(0, intensity, 1);
1680 // 1D gradient texture
1681 for (x = 0;x < ATTEN1DSIZE;x++)
1682 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1683 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);
1684 // 2D circle texture
1685 for (y = 0;y < ATTEN2DSIZE;y++)
1686 for (x = 0;x < ATTEN2DSIZE;x++)
1687 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);
1688 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);
1689 // 3D sphere texture
1690 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1692 for (z = 0;z < ATTEN3DSIZE;z++)
1693 for (y = 0;y < ATTEN3DSIZE;y++)
1694 for (x = 0;x < ATTEN3DSIZE;x++)
1695 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));
1696 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);
1699 r_shadow_attenuation3dtexture = NULL;
1702 R_Shadow_MakeTextures_MakeCorona();
1704 // Editor light sprites
1705 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1722 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1723 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1740 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1741 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1758 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1759 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1776 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1777 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1794 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1795 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1812 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1815 void R_Shadow_ValidateCvars(void)
1817 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1818 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1819 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1820 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1821 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1822 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1825 void R_Shadow_RenderMode_Begin(void)
1831 R_Shadow_ValidateCvars();
1833 if (!r_shadow_attenuation2dtexture
1834 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1835 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1836 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1837 R_Shadow_MakeTextures();
1840 R_Mesh_ColorPointer(NULL, 0, 0);
1841 R_Mesh_ResetTextureState();
1842 GL_BlendFunc(GL_ONE, GL_ZERO);
1843 GL_DepthRange(0, 1);
1844 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1846 GL_DepthMask(false);
1847 GL_Color(0, 0, 0, 1);
1848 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1850 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1852 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1854 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1855 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1857 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1859 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1860 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1864 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1865 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1868 if (r_glsl.integer && vid.support.arb_fragment_shader)
1869 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1870 else if (vid.support.arb_texture_env_dot3 && vid.support.arb_texture_cube_map && r_shadow_dot3.integer && vid.stencil)
1871 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1873 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1877 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1878 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1879 r_shadow_drawbuffer = drawbuffer;
1880 r_shadow_readbuffer = readbuffer;
1882 r_shadow_cullface_front = r_refdef.view.cullface_front;
1883 r_shadow_cullface_back = r_refdef.view.cullface_back;
1886 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1888 rsurface.rtlight = rtlight;
1891 void R_Shadow_RenderMode_Reset(void)
1894 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1896 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1898 if (vid.support.ext_framebuffer_object)
1900 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1903 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1904 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1906 R_SetViewport(&r_refdef.view.viewport);
1907 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1908 R_Mesh_ColorPointer(NULL, 0, 0);
1909 R_Mesh_ResetTextureState();
1910 GL_DepthRange(0, 1);
1912 GL_DepthMask(false);
1913 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1914 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1915 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1916 qglStencilMask(~0);CHECKGLERROR
1917 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1918 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1919 r_refdef.view.cullface_front = r_shadow_cullface_front;
1920 r_refdef.view.cullface_back = r_shadow_cullface_back;
1921 GL_CullFace(r_refdef.view.cullface_back);
1922 GL_Color(1, 1, 1, 1);
1923 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1924 GL_BlendFunc(GL_ONE, GL_ZERO);
1925 R_SetupGenericShader(false);
1926 r_shadow_usingshadowmaprect = false;
1927 r_shadow_usingshadowmapcube = false;
1928 r_shadow_usingshadowmap2d = false;
1932 void R_Shadow_ClearStencil(void)
1935 GL_Clear(GL_STENCIL_BUFFER_BIT);
1936 r_refdef.stats.lights_clears++;
1939 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1941 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1942 if (r_shadow_rendermode == mode)
1945 R_Shadow_RenderMode_Reset();
1946 GL_ColorMask(0, 0, 0, 0);
1947 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1948 R_SetupDepthOrShadowShader();
1949 qglDepthFunc(GL_LESS);CHECKGLERROR
1950 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1951 r_shadow_rendermode = mode;
1956 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1957 GL_CullFace(GL_NONE);
1958 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1959 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1961 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1962 GL_CullFace(GL_NONE);
1963 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1964 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1966 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1967 GL_CullFace(GL_NONE);
1968 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1969 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1970 qglStencilMask(~0);CHECKGLERROR
1971 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1972 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1973 qglStencilMask(~0);CHECKGLERROR
1974 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1976 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1977 GL_CullFace(GL_NONE);
1978 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1979 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1980 qglStencilMask(~0);CHECKGLERROR
1981 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1982 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1983 qglStencilMask(~0);CHECKGLERROR
1984 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1989 static void R_Shadow_MakeVSDCT(void)
1991 // maps to a 2x3 texture rectangle with normalized coordinates
1996 // stores abs(dir.xy), offset.xy/2.5
1997 unsigned char data[4*6] =
1999 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2000 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2001 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2002 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2003 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2004 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2006 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2009 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2013 float nearclip, farclip, bias;
2014 r_viewport_t viewport;
2017 maxsize = r_shadow_shadowmapmaxsize;
2018 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2020 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2021 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2022 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2023 r_shadow_shadowmapside = side;
2024 r_shadow_shadowmapsize = size;
2025 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2027 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2028 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2029 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2030 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2032 // complex unrolled cube approach (more flexible)
2033 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2034 R_Shadow_MakeVSDCT();
2035 if (!r_shadow_shadowmap2dtexture)
2038 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2039 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2040 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2041 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2042 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2043 // render depth into the fbo, do not render color at all
2044 qglDrawBuffer(GL_NONE);CHECKGLERROR
2045 qglReadBuffer(GL_NONE);CHECKGLERROR
2046 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2047 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2049 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2050 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2055 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2056 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2057 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2058 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2060 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2062 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2063 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2064 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2065 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2067 // complex unrolled cube approach (more flexible)
2068 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2069 R_Shadow_MakeVSDCT();
2070 if (!r_shadow_shadowmaprectangletexture)
2073 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2074 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2075 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2076 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2077 // render depth into the fbo, do not render color at all
2078 qglDrawBuffer(GL_NONE);CHECKGLERROR
2079 qglReadBuffer(GL_NONE);CHECKGLERROR
2080 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2081 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2083 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2084 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2089 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2090 r_shadow_shadowmap_texturescale[0] = 1.0f;
2091 r_shadow_shadowmap_texturescale[1] = 1.0f;
2092 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2094 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2096 r_shadow_shadowmap_parameters[0] = 1.0f;
2097 r_shadow_shadowmap_parameters[1] = 1.0f;
2098 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2099 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2101 // simple cube approach
2102 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2105 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2106 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2107 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2108 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
2109 // render depth into the fbo, do not render color at all
2110 qglDrawBuffer(GL_NONE);CHECKGLERROR
2111 qglReadBuffer(GL_NONE);CHECKGLERROR
2112 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2113 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2115 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2116 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2121 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2122 r_shadow_shadowmap_texturescale[0] = 0.0f;
2123 r_shadow_shadowmap_texturescale[1] = 0.0f;
2124 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2127 R_Shadow_RenderMode_Reset();
2130 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2131 R_SetupDepthOrShadowShader();
2135 R_SetupShowDepthShader();
2136 qglClearColor(1,1,1,1);CHECKGLERROR
2139 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2146 R_SetViewport(&viewport);
2147 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2148 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2150 int flipped = (side&1)^(side>>2);
2151 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2152 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2153 GL_CullFace(r_refdef.view.cullface_back);
2155 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2157 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
2160 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2164 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2168 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2169 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2170 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2171 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2174 R_Shadow_RenderMode_Reset();
2175 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2178 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2182 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2183 // only draw light where this geometry was already rendered AND the
2184 // stencil is 128 (values other than this mean shadow)
2185 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2187 r_shadow_rendermode = r_shadow_lightingrendermode;
2188 // do global setup needed for the chosen lighting mode
2189 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2191 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2192 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2196 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2198 r_shadow_usingshadowmap2d = true;
2199 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2202 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2204 r_shadow_usingshadowmaprect = true;
2205 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2208 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2210 r_shadow_usingshadowmapcube = true;
2211 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2215 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2217 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2222 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2223 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2227 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2230 R_Shadow_RenderMode_Reset();
2231 GL_BlendFunc(GL_ONE, GL_ONE);
2232 GL_DepthRange(0, 1);
2233 GL_DepthTest(r_showshadowvolumes.integer < 2);
2234 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2235 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2236 GL_CullFace(GL_NONE);
2237 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2240 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2243 R_Shadow_RenderMode_Reset();
2244 GL_BlendFunc(GL_ONE, GL_ONE);
2245 GL_DepthRange(0, 1);
2246 GL_DepthTest(r_showlighting.integer < 2);
2247 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2250 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2254 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2255 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2257 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2260 void R_Shadow_RenderMode_End(void)
2263 R_Shadow_RenderMode_Reset();
2264 R_Shadow_RenderMode_ActiveLight(NULL);
2266 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2267 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2270 int bboxedges[12][2] =
2289 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2291 int i, ix1, iy1, ix2, iy2;
2292 float x1, y1, x2, y2;
2294 float vertex[20][3];
2303 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2304 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2305 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2306 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2308 if (!r_shadow_scissor.integer)
2311 // if view is inside the light box, just say yes it's visible
2312 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2315 x1 = y1 = x2 = y2 = 0;
2317 // transform all corners that are infront of the nearclip plane
2318 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2319 plane4f[3] = r_refdef.view.frustum[4].dist;
2321 for (i = 0;i < 8;i++)
2323 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2324 dist[i] = DotProduct4(corner[i], plane4f);
2325 sign[i] = dist[i] > 0;
2328 VectorCopy(corner[i], vertex[numvertices]);
2332 // if some points are behind the nearclip, add clipped edge points to make
2333 // sure that the scissor boundary is complete
2334 if (numvertices > 0 && numvertices < 8)
2336 // add clipped edge points
2337 for (i = 0;i < 12;i++)
2339 j = bboxedges[i][0];
2340 k = bboxedges[i][1];
2341 if (sign[j] != sign[k])
2343 f = dist[j] / (dist[j] - dist[k]);
2344 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2350 // if we have no points to check, the light is behind the view plane
2354 // if we have some points to transform, check what screen area is covered
2355 x1 = y1 = x2 = y2 = 0;
2357 //Con_Printf("%i vertices to transform...\n", numvertices);
2358 for (i = 0;i < numvertices;i++)
2360 VectorCopy(vertex[i], v);
2361 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2362 //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]);
2365 if (x1 > v2[0]) x1 = v2[0];
2366 if (x2 < v2[0]) x2 = v2[0];
2367 if (y1 > v2[1]) y1 = v2[1];
2368 if (y2 < v2[1]) y2 = v2[1];
2377 // now convert the scissor rectangle to integer screen coordinates
2378 ix1 = (int)(x1 - 1.0f);
2379 iy1 = vid.height - (int)(y2 - 1.0f);
2380 ix2 = (int)(x2 + 1.0f);
2381 iy2 = vid.height - (int)(y1 + 1.0f);
2382 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2384 // clamp it to the screen
2385 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2386 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2387 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2388 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2390 // if it is inside out, it's not visible
2391 if (ix2 <= ix1 || iy2 <= iy1)
2394 // the light area is visible, set up the scissor rectangle
2395 r_shadow_lightscissor[0] = ix1;
2396 r_shadow_lightscissor[1] = iy1;
2397 r_shadow_lightscissor[2] = ix2 - ix1;
2398 r_shadow_lightscissor[3] = iy2 - iy1;
2400 r_refdef.stats.lights_scissored++;
2404 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2406 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2407 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2408 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2409 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2410 if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2412 if (VectorLength2(diffusecolor) > 0)
2414 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2416 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2417 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2418 if ((dot = DotProduct(n, v)) < 0)
2420 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2421 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2424 VectorCopy(ambientcolor, color4f);
2425 if (r_refdef.fogenabled)
2428 f = RSurf_FogVertex(vertex3f);
2429 VectorScale(color4f, f, color4f);
2436 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2438 VectorCopy(ambientcolor, color4f);
2439 if (r_refdef.fogenabled)
2442 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2443 f = RSurf_FogVertex(vertex3f);
2444 VectorScale(color4f, f, color4f);
2450 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2452 if (VectorLength2(diffusecolor) > 0)
2454 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2456 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2457 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2459 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2460 if ((dot = DotProduct(n, v)) < 0)
2462 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2463 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2464 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2465 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2469 color4f[0] = ambientcolor[0] * distintensity;
2470 color4f[1] = ambientcolor[1] * distintensity;
2471 color4f[2] = ambientcolor[2] * distintensity;
2473 if (r_refdef.fogenabled)
2476 f = RSurf_FogVertex(vertex3f);
2477 VectorScale(color4f, f, color4f);
2481 VectorClear(color4f);
2487 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2489 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2490 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2492 color4f[0] = ambientcolor[0] * distintensity;
2493 color4f[1] = ambientcolor[1] * distintensity;
2494 color4f[2] = ambientcolor[2] * distintensity;
2495 if (r_refdef.fogenabled)
2498 f = RSurf_FogVertex(vertex3f);
2499 VectorScale(color4f, f, color4f);
2503 VectorClear(color4f);
2510 if (VectorLength2(diffusecolor) > 0)
2512 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2514 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2515 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2517 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2518 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2519 if ((dot = DotProduct(n, v)) < 0)
2521 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2522 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2523 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2524 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2528 color4f[0] = ambientcolor[0] * distintensity;
2529 color4f[1] = ambientcolor[1] * distintensity;
2530 color4f[2] = ambientcolor[2] * distintensity;
2532 if (r_refdef.fogenabled)
2535 f = RSurf_FogVertex(vertex3f);
2536 VectorScale(color4f, f, color4f);
2540 VectorClear(color4f);
2546 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2548 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2549 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2551 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2552 color4f[0] = ambientcolor[0] * distintensity;
2553 color4f[1] = ambientcolor[1] * distintensity;
2554 color4f[2] = ambientcolor[2] * distintensity;
2555 if (r_refdef.fogenabled)
2558 f = RSurf_FogVertex(vertex3f);
2559 VectorScale(color4f, f, color4f);
2563 VectorClear(color4f);
2570 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2572 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2575 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2576 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2577 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2578 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2579 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2581 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2583 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2584 // the cubemap normalizes this for us
2585 out3f[0] = DotProduct(svector3f, lightdir);
2586 out3f[1] = DotProduct(tvector3f, lightdir);
2587 out3f[2] = DotProduct(normal3f, lightdir);
2591 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2594 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2595 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2596 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2597 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2598 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2599 float lightdir[3], eyedir[3], halfdir[3];
2600 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2602 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2603 VectorNormalize(lightdir);
2604 VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir);
2605 VectorNormalize(eyedir);
2606 VectorAdd(lightdir, eyedir, halfdir);
2607 // the cubemap normalizes this for us
2608 out3f[0] = DotProduct(svector3f, halfdir);
2609 out3f[1] = DotProduct(tvector3f, halfdir);
2610 out3f[2] = DotProduct(normal3f, halfdir);
2614 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)
2616 // used to display how many times a surface is lit for level design purposes
2617 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2620 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)
2622 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2623 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2624 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2625 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2627 R_Mesh_ColorPointer(NULL, 0, 0);
2628 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2629 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2630 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2631 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2632 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2633 if (rsurface.texture->backgroundcurrentskinframe)
2635 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2636 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2637 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2638 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2640 //R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
2641 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2642 if(rsurface.texture->colormapping)
2644 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2645 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2647 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2648 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2649 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2650 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2651 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2652 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2654 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2656 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2657 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2659 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2663 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)
2665 // shared final code for all the dot3 layers
2667 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2668 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2670 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2671 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2675 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)
2678 // colorscale accounts for how much we multiply the brightness
2681 // mult is how many times the final pass of the lighting will be
2682 // performed to get more brightness than otherwise possible.
2684 // Limit mult to 64 for sanity sake.
2686 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2688 // 3 3D combine path (Geforce3, Radeon 8500)
2689 memset(&m, 0, sizeof(m));
2690 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2691 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2692 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2693 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2694 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2695 m.tex[1] = R_GetTexture(basetexture);
2696 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2697 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2698 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2699 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2700 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2701 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2702 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2703 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2704 m.texmatrix[2] = rsurface.entitytolight;
2705 GL_BlendFunc(GL_ONE, GL_ONE);
2707 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2709 // 2 3D combine path (Geforce3, original Radeon)
2710 memset(&m, 0, sizeof(m));
2711 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2712 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2713 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2714 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2715 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2716 m.tex[1] = R_GetTexture(basetexture);
2717 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2718 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2719 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2720 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2721 GL_BlendFunc(GL_ONE, GL_ONE);
2723 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2725 // 4 2D combine path (Geforce3, Radeon 8500)
2726 memset(&m, 0, sizeof(m));
2727 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2728 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2729 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2730 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2731 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2732 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2733 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2734 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2735 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2736 m.texmatrix[1] = rsurface.entitytoattenuationz;
2737 m.tex[2] = R_GetTexture(basetexture);
2738 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2739 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2740 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2741 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2742 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2744 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2745 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2746 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2747 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2748 m.texmatrix[3] = rsurface.entitytolight;
2750 GL_BlendFunc(GL_ONE, GL_ONE);
2752 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2754 // 3 2D combine path (Geforce3, original Radeon)
2755 memset(&m, 0, sizeof(m));
2756 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2757 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2758 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2759 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2760 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2761 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2762 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2763 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2764 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2765 m.texmatrix[1] = rsurface.entitytoattenuationz;
2766 m.tex[2] = R_GetTexture(basetexture);
2767 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2768 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2769 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2770 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2771 GL_BlendFunc(GL_ONE, GL_ONE);
2775 // 2/2/2 2D combine path (any dot3 card)
2776 memset(&m, 0, sizeof(m));
2777 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2778 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2779 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2780 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2781 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2782 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2783 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2784 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2785 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2786 m.texmatrix[1] = rsurface.entitytoattenuationz;
2787 R_Mesh_TextureState(&m);
2788 GL_ColorMask(0,0,0,1);
2789 GL_BlendFunc(GL_ONE, GL_ZERO);
2790 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2793 memset(&m, 0, sizeof(m));
2794 m.tex[0] = R_GetTexture(basetexture);
2795 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2796 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2797 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2798 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2799 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2801 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2802 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2803 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2804 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2805 m.texmatrix[1] = rsurface.entitytolight;
2807 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2809 // this final code is shared
2810 R_Mesh_TextureState(&m);
2811 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);
2814 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)
2817 // colorscale accounts for how much we multiply the brightness
2820 // mult is how many times the final pass of the lighting will be
2821 // performed to get more brightness than otherwise possible.
2823 // Limit mult to 64 for sanity sake.
2825 // generate normalization cubemap texcoords
2826 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2827 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2829 // 3/2 3D combine path (Geforce3, Radeon 8500)
2830 memset(&m, 0, sizeof(m));
2831 m.tex[0] = R_GetTexture(normalmaptexture);
2832 m.texcombinergb[0] = GL_REPLACE;
2833 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2834 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2835 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2836 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2837 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2838 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2839 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2840 m.pointer_texcoord_bufferobject[1] = 0;
2841 m.pointer_texcoord_bufferoffset[1] = 0;
2842 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2843 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2844 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2845 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2846 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2847 R_Mesh_TextureState(&m);
2848 GL_ColorMask(0,0,0,1);
2849 GL_BlendFunc(GL_ONE, GL_ZERO);
2850 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2853 memset(&m, 0, sizeof(m));
2854 m.tex[0] = R_GetTexture(basetexture);
2855 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2856 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2857 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2858 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2859 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2861 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2862 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2863 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2864 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2865 m.texmatrix[1] = rsurface.entitytolight;
2867 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2869 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2871 // 1/2/2 3D combine path (original Radeon)
2872 memset(&m, 0, sizeof(m));
2873 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2874 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2875 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2876 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2877 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2878 R_Mesh_TextureState(&m);
2879 GL_ColorMask(0,0,0,1);
2880 GL_BlendFunc(GL_ONE, GL_ZERO);
2881 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2884 memset(&m, 0, sizeof(m));
2885 m.tex[0] = R_GetTexture(normalmaptexture);
2886 m.texcombinergb[0] = GL_REPLACE;
2887 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2888 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2889 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2890 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2891 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2892 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2893 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2894 m.pointer_texcoord_bufferobject[1] = 0;
2895 m.pointer_texcoord_bufferoffset[1] = 0;
2896 R_Mesh_TextureState(&m);
2897 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2898 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2901 memset(&m, 0, sizeof(m));
2902 m.tex[0] = R_GetTexture(basetexture);
2903 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2904 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2905 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2906 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2907 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2909 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2910 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2911 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2912 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2913 m.texmatrix[1] = rsurface.entitytolight;
2915 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2917 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2919 // 2/2 3D combine path (original Radeon)
2920 memset(&m, 0, sizeof(m));
2921 m.tex[0] = R_GetTexture(normalmaptexture);
2922 m.texcombinergb[0] = GL_REPLACE;
2923 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2924 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2925 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2926 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2927 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2928 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2929 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2930 m.pointer_texcoord_bufferobject[1] = 0;
2931 m.pointer_texcoord_bufferoffset[1] = 0;
2932 R_Mesh_TextureState(&m);
2933 GL_ColorMask(0,0,0,1);
2934 GL_BlendFunc(GL_ONE, GL_ZERO);
2935 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2938 memset(&m, 0, sizeof(m));
2939 m.tex[0] = R_GetTexture(basetexture);
2940 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2941 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2942 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2943 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2944 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2945 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2946 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2947 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2948 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2949 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2951 else if (r_textureunits.integer >= 4)
2953 // 4/2 2D combine path (Geforce3, Radeon 8500)
2954 memset(&m, 0, sizeof(m));
2955 m.tex[0] = R_GetTexture(normalmaptexture);
2956 m.texcombinergb[0] = GL_REPLACE;
2957 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2958 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2959 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2960 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2961 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2962 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2963 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2964 m.pointer_texcoord_bufferobject[1] = 0;
2965 m.pointer_texcoord_bufferoffset[1] = 0;
2966 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2967 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2968 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2969 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2970 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2971 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2972 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2973 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2974 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2975 m.texmatrix[3] = rsurface.entitytoattenuationz;
2976 R_Mesh_TextureState(&m);
2977 GL_ColorMask(0,0,0,1);
2978 GL_BlendFunc(GL_ONE, GL_ZERO);
2979 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2982 memset(&m, 0, sizeof(m));
2983 m.tex[0] = R_GetTexture(basetexture);
2984 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2985 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2986 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2987 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2988 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2990 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2991 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2992 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2993 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2994 m.texmatrix[1] = rsurface.entitytolight;
2996 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3000 // 2/2/2 2D combine path (any dot3 card)
3001 memset(&m, 0, sizeof(m));
3002 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3003 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3004 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3005 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3006 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3007 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3008 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3009 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3010 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3011 m.texmatrix[1] = rsurface.entitytoattenuationz;
3012 R_Mesh_TextureState(&m);
3013 GL_ColorMask(0,0,0,1);
3014 GL_BlendFunc(GL_ONE, GL_ZERO);
3015 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3018 memset(&m, 0, sizeof(m));
3019 m.tex[0] = R_GetTexture(normalmaptexture);
3020 m.texcombinergb[0] = GL_REPLACE;
3021 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3022 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3023 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3024 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3025 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3026 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3027 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3028 m.pointer_texcoord_bufferobject[1] = 0;
3029 m.pointer_texcoord_bufferoffset[1] = 0;
3030 R_Mesh_TextureState(&m);
3031 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3032 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3035 memset(&m, 0, sizeof(m));
3036 m.tex[0] = R_GetTexture(basetexture);
3037 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3038 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3039 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3040 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3041 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3043 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3044 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3045 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3046 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3047 m.texmatrix[1] = rsurface.entitytolight;
3049 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3051 // this final code is shared
3052 R_Mesh_TextureState(&m);
3053 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);
3056 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)
3058 float glossexponent;
3060 // FIXME: detect blendsquare!
3061 //if (!gl_support_blendsquare)
3064 // generate normalization cubemap texcoords
3065 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
3066 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
3068 // 2/0/0/1/2 3D combine blendsquare path
3069 memset(&m, 0, sizeof(m));
3070 m.tex[0] = R_GetTexture(normalmaptexture);
3071 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3072 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3073 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3074 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3075 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3076 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3077 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3078 m.pointer_texcoord_bufferobject[1] = 0;
3079 m.pointer_texcoord_bufferoffset[1] = 0;
3080 R_Mesh_TextureState(&m);
3081 GL_ColorMask(0,0,0,1);
3082 // this squares the result
3083 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3084 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3086 // second and third pass
3087 R_Mesh_ResetTextureState();
3088 // square alpha in framebuffer a few times to make it shiny
3089 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3090 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3091 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3094 memset(&m, 0, sizeof(m));
3095 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3096 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3097 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3098 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3099 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3100 R_Mesh_TextureState(&m);
3101 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3102 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3105 memset(&m, 0, sizeof(m));
3106 m.tex[0] = R_GetTexture(glosstexture);
3107 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3108 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3109 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3110 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3111 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3113 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3114 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3115 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3116 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3117 m.texmatrix[1] = rsurface.entitytolight;
3119 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3121 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3123 // 2/0/0/2 3D combine blendsquare path
3124 memset(&m, 0, sizeof(m));
3125 m.tex[0] = R_GetTexture(normalmaptexture);
3126 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3127 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3128 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3129 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3130 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3131 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3132 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3133 m.pointer_texcoord_bufferobject[1] = 0;
3134 m.pointer_texcoord_bufferoffset[1] = 0;
3135 R_Mesh_TextureState(&m);
3136 GL_ColorMask(0,0,0,1);
3137 // this squares the result
3138 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3139 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3141 // second and third pass
3142 R_Mesh_ResetTextureState();
3143 // square alpha in framebuffer a few times to make it shiny
3144 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3145 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3146 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3149 memset(&m, 0, sizeof(m));
3150 m.tex[0] = R_GetTexture(glosstexture);
3151 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3152 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3153 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3154 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3155 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3156 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3157 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3158 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3159 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3160 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3164 // 2/0/0/2/2 2D combine blendsquare path
3165 memset(&m, 0, sizeof(m));
3166 m.tex[0] = R_GetTexture(normalmaptexture);
3167 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3168 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3169 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3170 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3171 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3172 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3173 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3174 m.pointer_texcoord_bufferobject[1] = 0;
3175 m.pointer_texcoord_bufferoffset[1] = 0;
3176 R_Mesh_TextureState(&m);
3177 GL_ColorMask(0,0,0,1);
3178 // this squares the result
3179 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3180 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3182 // second and third pass
3183 R_Mesh_ResetTextureState();
3184 // square alpha in framebuffer a few times to make it shiny
3185 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3186 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3187 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3190 memset(&m, 0, sizeof(m));
3191 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3192 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3193 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3194 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3195 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3196 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3197 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3198 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3199 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3200 m.texmatrix[1] = rsurface.entitytoattenuationz;
3201 R_Mesh_TextureState(&m);
3202 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3203 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3206 memset(&m, 0, sizeof(m));
3207 m.tex[0] = R_GetTexture(glosstexture);
3208 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3209 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3210 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3211 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3212 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3214 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3215 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3216 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3217 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3218 m.texmatrix[1] = rsurface.entitytolight;
3220 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3222 // this final code is shared
3223 R_Mesh_TextureState(&m);
3224 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);
3227 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)
3229 // ARB path (any Geforce, any Radeon)
3230 qboolean doambient = ambientscale > 0;
3231 qboolean dodiffuse = diffusescale > 0;
3232 qboolean dospecular = specularscale > 0;
3233 if (!doambient && !dodiffuse && !dospecular)
3235 R_Mesh_ColorPointer(NULL, 0, 0);
3237 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3239 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3243 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3245 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3250 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3252 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3255 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3258 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3265 int newnumtriangles;
3269 int maxtriangles = 4096;
3270 int newelements[4096*3];
3271 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3272 for (renders = 0;renders < 64;renders++)
3277 newnumtriangles = 0;
3279 // due to low fillrate on the cards this vertex lighting path is
3280 // designed for, we manually cull all triangles that do not
3281 // contain a lit vertex
3282 // this builds batches of triangles from multiple surfaces and
3283 // renders them at once
3284 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3286 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3288 if (newnumtriangles)
3290 newfirstvertex = min(newfirstvertex, e[0]);
3291 newlastvertex = max(newlastvertex, e[0]);
3295 newfirstvertex = e[0];
3296 newlastvertex = e[0];
3298 newfirstvertex = min(newfirstvertex, e[1]);
3299 newlastvertex = max(newlastvertex, e[1]);
3300 newfirstvertex = min(newfirstvertex, e[2]);
3301 newlastvertex = max(newlastvertex, e[2]);
3307 if (newnumtriangles >= maxtriangles)
3309 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3310 newnumtriangles = 0;
3316 if (newnumtriangles >= 1)
3318 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3321 // if we couldn't find any lit triangles, exit early
3324 // now reduce the intensity for the next overbright pass
3325 // we have to clamp to 0 here incase the drivers have improper
3326 // handling of negative colors
3327 // (some old drivers even have improper handling of >1 color)
3329 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3331 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3333 c[0] = max(0, c[0] - 1);
3334 c[1] = max(0, c[1] - 1);
3335 c[2] = max(0, c[2] - 1);
3347 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)
3349 // OpenGL 1.1 path (anything)
3350 float ambientcolorbase[3], diffusecolorbase[3];
3351 float ambientcolorpants[3], diffusecolorpants[3];
3352 float ambientcolorshirt[3], diffusecolorshirt[3];
3354 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3355 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3356 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3357 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3358 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3359 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3360 memset(&m, 0, sizeof(m));
3361 m.tex[0] = R_GetTexture(basetexture);
3362 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3363 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3364 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3365 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3366 if (r_textureunits.integer >= 2 && vid.texunits >= 2)
3369 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3370 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3371 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3372 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3373 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3374 if (r_textureunits.integer >= 3 && vid.texunits >= 3)
3376 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3377 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3378 m.texmatrix[2] = rsurface.entitytoattenuationz;
3379 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3380 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3381 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3384 R_Mesh_TextureState(&m);
3385 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3386 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3389 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3390 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3394 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3395 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3399 extern cvar_t gl_lightmaps;
3400 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)
3402 float ambientscale, diffusescale, specularscale;
3404 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3406 // calculate colors to render this texture with
3407 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3408 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3409 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3410 ambientscale = rsurface.rtlight->ambientscale;
3411 diffusescale = rsurface.rtlight->diffusescale;
3412 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3413 if (!r_shadow_usenormalmap.integer)
3415 ambientscale += 1.0f * diffusescale;
3419 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3421 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
3424 VectorNegate(lightcolorbase, lightcolorbase);
3425 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3427 RSurf_SetupDepthAndCulling();
3428 nmap = rsurface.texture->currentskinframe->nmap;
3429 if (gl_lightmaps.integer)
3430 nmap = r_texture_blanknormalmap;
3431 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3433 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3434 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3437 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3438 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3439 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3442 VectorClear(lightcolorpants);
3445 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3446 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3447 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3450 VectorClear(lightcolorshirt);
3451 switch (r_shadow_rendermode)
3453 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3454 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3455 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);
3457 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3458 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);
3460 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3461 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);
3463 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3464 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);
3467 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3473 switch (r_shadow_rendermode)
3475 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3476 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3477 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);
3479 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3480 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);
3482 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3483 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);
3485 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3486 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);
3489 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3494 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3497 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)
3499 matrix4x4_t tempmatrix = *matrix;
3500 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3502 // if this light has been compiled before, free the associated data
3503 R_RTLight_Uncompile(rtlight);
3505 // clear it completely to avoid any lingering data
3506 memset(rtlight, 0, sizeof(*rtlight));
3508 // copy the properties
3509 rtlight->matrix_lighttoworld = tempmatrix;
3510 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3511 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3512 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3513 VectorCopy(color, rtlight->color);
3514 rtlight->cubemapname[0] = 0;
3515 if (cubemapname && cubemapname[0])
3516 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3517 rtlight->shadow = shadow;
3518 rtlight->corona = corona;
3519 rtlight->style = style;
3520 rtlight->isstatic = isstatic;
3521 rtlight->coronasizescale = coronasizescale;
3522 rtlight->ambientscale = ambientscale;
3523 rtlight->diffusescale = diffusescale;
3524 rtlight->specularscale = specularscale;
3525 rtlight->flags = flags;
3527 // compute derived data
3528 //rtlight->cullradius = rtlight->radius;
3529 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3530 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3531 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3532 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3533 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3534 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3535 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3538 // compiles rtlight geometry
3539 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3540 void R_RTLight_Compile(rtlight_t *rtlight)
3543 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3544 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3545 entity_render_t *ent = r_refdef.scene.worldentity;
3546 dp_model_t *model = r_refdef.scene.worldmodel;
3547 unsigned char *data;
3550 // compile the light
3551 rtlight->compiled = true;
3552 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3553 rtlight->static_numleafs = 0;
3554 rtlight->static_numleafpvsbytes = 0;
3555 rtlight->static_leaflist = NULL;
3556 rtlight->static_leafpvs = NULL;
3557 rtlight->static_numsurfaces = 0;
3558 rtlight->static_surfacelist = NULL;
3559 rtlight->static_shadowmap_receivers = 0x3F;
3560 rtlight->static_shadowmap_casters = 0x3F;
3561 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3562 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3563 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3564 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3565 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3566 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3568 if (model && model->GetLightInfo)
3570 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3571 r_shadow_compilingrtlight = rtlight;
3572 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);
3573 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);
3574 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3575 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3576 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3577 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3578 rtlight->static_numsurfaces = numsurfaces;
3579 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3580 rtlight->static_numleafs = numleafs;
3581 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3582 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3583 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3584 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3585 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3586 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3587 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3588 if (rtlight->static_numsurfaces)
3589 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3590 if (rtlight->static_numleafs)
3591 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3592 if (rtlight->static_numleafpvsbytes)
3593 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3594 if (rtlight->static_numshadowtrispvsbytes)
3595 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3596 if (rtlight->static_numlighttrispvsbytes)
3597 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3598 switch (rtlight->shadowmode)
3600 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3601 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3602 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3603 if (model->CompileShadowMap && rtlight->shadow)
3604 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3607 if (model->CompileShadowVolume && rtlight->shadow)
3608 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3611 // now we're done compiling the rtlight
3612 r_shadow_compilingrtlight = NULL;
3616 // use smallest available cullradius - box radius or light radius
3617 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3618 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3620 shadowzpasstris = 0;
3621 if (rtlight->static_meshchain_shadow_zpass)
3622 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3623 shadowzpasstris += mesh->numtriangles;
3625 shadowzfailtris = 0;
3626 if (rtlight->static_meshchain_shadow_zfail)
3627 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3628 shadowzfailtris += mesh->numtriangles;
3631 if (rtlight->static_numlighttrispvsbytes)
3632 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3633 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3637 if (rtlight->static_numlighttrispvsbytes)
3638 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3639 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3642 if (developer.integer >= 10)
3643 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);
3646 void R_RTLight_Uncompile(rtlight_t *rtlight)
3648 if (rtlight->compiled)
3650 if (rtlight->static_meshchain_shadow_zpass)
3651 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3652 rtlight->static_meshchain_shadow_zpass = NULL;
3653 if (rtlight->static_meshchain_shadow_zfail)
3654 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3655 rtlight->static_meshchain_shadow_zfail = NULL;
3656 if (rtlight->static_meshchain_shadow_shadowmap)
3657 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3658 rtlight->static_meshchain_shadow_shadowmap = NULL;
3659 // these allocations are grouped
3660 if (rtlight->static_surfacelist)
3661 Mem_Free(rtlight->static_surfacelist);
3662 rtlight->static_numleafs = 0;
3663 rtlight->static_numleafpvsbytes = 0;
3664 rtlight->static_leaflist = NULL;
3665 rtlight->static_leafpvs = NULL;
3666 rtlight->static_numsurfaces = 0;
3667 rtlight->static_surfacelist = NULL;
3668 rtlight->static_numshadowtrispvsbytes = 0;
3669 rtlight->static_shadowtrispvs = NULL;
3670 rtlight->static_numlighttrispvsbytes = 0;
3671 rtlight->static_lighttrispvs = NULL;
3672 rtlight->compiled = false;
3676 void R_Shadow_UncompileWorldLights(void)
3680 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3681 for (lightindex = 0;lightindex < range;lightindex++)
3683 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3686 R_RTLight_Uncompile(&light->rtlight);
3690 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3694 // reset the count of frustum planes
3695 // see rsurface.rtlight_frustumplanes definition for how much this array
3697 rsurface.rtlight_numfrustumplanes = 0;
3699 // haven't implemented a culling path for ortho rendering
3700 if (!r_refdef.view.useperspective)
3702 // check if the light is on screen and copy the 4 planes if it is
3703 for (i = 0;i < 4;i++)
3704 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3707 for (i = 0;i < 4;i++)
3708 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3713 // generate a deformed frustum that includes the light origin, this is
3714 // used to cull shadow casting surfaces that can not possibly cast a
3715 // shadow onto the visible light-receiving surfaces, which can be a
3718 // if the light origin is onscreen the result will be 4 planes exactly
3719 // if the light origin is offscreen on only one axis the result will
3720 // be exactly 5 planes (split-side case)
3721 // if the light origin is offscreen on two axes the result will be
3722 // exactly 4 planes (stretched corner case)
3723 for (i = 0;i < 4;i++)
3725 // quickly reject standard frustum planes that put the light
3726 // origin outside the frustum
3727 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3730 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3732 // if all the standard frustum planes were accepted, the light is onscreen
3733 // otherwise we need to generate some more planes below...
3734 if (rsurface.rtlight_numfrustumplanes < 4)
3736 // at least one of the stock frustum planes failed, so we need to
3737 // create one or two custom planes to enclose the light origin
3738 for (i = 0;i < 4;i++)
3740 // create a plane using the view origin and light origin, and a
3741 // single point from the frustum corner set
3742 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3743 VectorNormalize(plane.normal);
3744 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3745 // see if this plane is backwards and flip it if so
3746 for (j = 0;j < 4;j++)
3747 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3751 VectorNegate(plane.normal, plane.normal);
3753 // flipped plane, test again to see if it is now valid
3754 for (j = 0;j < 4;j++)
3755 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3757 // if the plane is still not valid, then it is dividing the
3758 // frustum and has to be rejected
3762 // we have created a valid plane, compute extra info
3763 PlaneClassify(&plane);
3765 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3767 // if we've found 5 frustum planes then we have constructed a
3768 // proper split-side case and do not need to keep searching for
3769 // planes to enclose the light origin
3770 if (rsurface.rtlight_numfrustumplanes == 5)
3778 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3780 plane = rsurface.rtlight_frustumplanes[i];
3781 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));
3786 // now add the light-space box planes if the light box is rotated, as any
3787 // caster outside the oriented light box is irrelevant (even if it passed
3788 // the worldspace light box, which is axial)
3789 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3791 for (i = 0;i < 6;i++)
3795 v[i >> 1] = (i & 1) ? -1 : 1;
3796 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3797 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3798 plane.dist = VectorNormalizeLength(plane.normal);
3799 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3800 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3806 // add the world-space reduced box planes
3807 for (i = 0;i < 6;i++)
3809 VectorClear(plane.normal);
3810 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3811 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3812 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3821 // reduce all plane distances to tightly fit the rtlight cull box, which
3823 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3824 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3825 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3826 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3827 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3828 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3829 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3830 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3831 oldnum = rsurface.rtlight_numfrustumplanes;
3832 rsurface.rtlight_numfrustumplanes = 0;
3833 for (j = 0;j < oldnum;j++)
3835 // find the nearest point on the box to this plane
3836 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3837 for (i = 1;i < 8;i++)
3839 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3840 if (bestdist > dist)
3843 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);
3844 // if the nearest point is near or behind the plane, we want this
3845 // plane, otherwise the plane is useless as it won't cull anything
3846 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3848 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3849 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3856 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3860 RSurf_ActiveWorldEntity();
3862 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3865 GL_CullFace(GL_NONE);
3866 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3867 for (;mesh;mesh = mesh->next)
3869 if (!mesh->sidetotals[r_shadow_shadowmapside])
3871 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3872 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3873 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3877 else if (r_refdef.scene.worldentity->model)
3878 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);
3880 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3883 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3888 int surfacelistindex;
3889 msurface_t *surface;
3891 RSurf_ActiveWorldEntity();
3893 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3896 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3897 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3898 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3899 for (;mesh;mesh = mesh->next)
3901 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3902 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3903 GL_LockArrays(0, mesh->numverts);
3904 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3906 // increment stencil if frontface is infront of depthbuffer
3907 GL_CullFace(r_refdef.view.cullface_back);
3908 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3909 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3910 // decrement stencil if backface is infront of depthbuffer
3911 GL_CullFace(r_refdef.view.cullface_front);
3912 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3914 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3916 // decrement stencil if backface is behind depthbuffer
3917 GL_CullFace(r_refdef.view.cullface_front);
3918 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3919 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3920 // increment stencil if frontface is behind depthbuffer
3921 GL_CullFace(r_refdef.view.cullface_back);
3922 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3924 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3925 GL_LockArrays(0, 0);
3929 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3931 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3932 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3934 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3935 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3936 if (CHECKPVSBIT(trispvs, t))
3937 shadowmarklist[numshadowmark++] = t;
3939 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);
3941 else if (numsurfaces)
3942 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3944 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3947 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3949 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3950 vec_t relativeshadowradius;
3951 RSurf_ActiveModelEntity(ent, false, false);
3952 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3953 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3954 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3955 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3956 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3957 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3958 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3959 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3960 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3962 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3965 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3966 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3969 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3971 // set up properties for rendering light onto this entity
3972 RSurf_ActiveModelEntity(ent, true, true);
3973 GL_AlphaTest(false);
3974 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3975 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3976 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3977 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3978 switch(r_shadow_lightingrendermode)
3980 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3981 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3988 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3990 if (!r_refdef.scene.worldmodel->DrawLight)
3993 // set up properties for rendering light onto this entity
3994 RSurf_ActiveWorldEntity();
3995 GL_AlphaTest(false);
3996 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3997 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3998 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3999 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4000 switch(r_shadow_lightingrendermode)
4002 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4003 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
4009 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
4011 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4014 void R_Shadow_DrawEntityLight(entity_render_t *ent)
4016 dp_model_t *model = ent->model;
4017 if (!model->DrawLight)
4020 R_Shadow_SetupEntityLight(ent);
4022 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4024 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4027 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
4031 int numleafs, numsurfaces;
4032 int *leaflist, *surfacelist;
4033 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
4034 int numlightentities;
4035 int numlightentities_noselfshadow;
4036 int numshadowentities;
4037 int numshadowentities_noselfshadow;
4038 static entity_render_t *lightentities[MAX_EDICTS];
4039 static entity_render_t *shadowentities[MAX_EDICTS];
4040 static unsigned char entitysides[MAX_EDICTS];
4041 int lightentities_noselfshadow;
4042 int shadowentities_noselfshadow;
4043 vec3_t nearestpoint;
4045 qboolean castshadows;
4048 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4049 // skip lights that are basically invisible (color 0 0 0)
4050 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
4053 // loading is done before visibility checks because loading should happen
4054 // all at once at the start of a level, not when it stalls gameplay.
4055 // (especially important to benchmarks)
4057 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4059 if (rtlight->compiled)
4060 R_RTLight_Uncompile(rtlight);
4061 R_RTLight_Compile(rtlight);
4065 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
4067 // look up the light style value at this time
4068 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4069 VectorScale(rtlight->color, f, rtlight->currentcolor);
4071 if (rtlight->selected)
4073 f = 2 + sin(realtime * M_PI * 4.0);
4074 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4078 // if lightstyle is currently off, don't draw the light
4079 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4082 // if the light box is offscreen, skip it
4083 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4086 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
4087 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
4089 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4091 // compiled light, world available and can receive realtime lighting
4092 // retrieve leaf information
4093 numleafs = rtlight->static_numleafs;
4094 leaflist = rtlight->static_leaflist;
4095 leafpvs = rtlight->static_leafpvs;
4096 numsurfaces = rtlight->static_numsurfaces;
4097 surfacelist = rtlight->static_surfacelist;
4098 surfacesides = NULL;
4099 shadowtrispvs = rtlight->static_shadowtrispvs;
4100 lighttrispvs = rtlight->static_lighttrispvs;
4102 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4104 // dynamic light, world available and can receive realtime lighting
4105 // calculate lit surfaces and leafs
4106 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);
4107 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);
4108 leaflist = r_shadow_buffer_leaflist;
4109 leafpvs = r_shadow_buffer_leafpvs;
4110 surfacelist = r_shadow_buffer_surfacelist;
4111 surfacesides = r_shadow_buffer_surfacesides;
4112 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4113 lighttrispvs = r_shadow_buffer_lighttrispvs;
4114 // if the reduced leaf bounds are offscreen, skip it
4115 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4126 surfacesides = NULL;
4127 shadowtrispvs = NULL;
4128 lighttrispvs = NULL;
4130 // check if light is illuminating any visible leafs
4133 for (i = 0;i < numleafs;i++)
4134 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4139 // set up a scissor rectangle for this light
4140 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4143 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4145 // make a list of lit entities and shadow casting entities
4146 numlightentities = 0;
4147 numlightentities_noselfshadow = 0;
4148 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4149 numshadowentities = 0;
4150 numshadowentities_noselfshadow = 0;
4151 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4153 // add dynamic entities that are lit by the light
4154 if (r_drawentities.integer)
4156 for (i = 0;i < r_refdef.scene.numentities;i++)
4159 entity_render_t *ent = r_refdef.scene.entities[i];
4161 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4163 // skip the object entirely if it is not within the valid
4164 // shadow-casting region (which includes the lit region)
4165 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4167 if (!(model = ent->model))
4169 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4171 // this entity wants to receive light, is visible, and is
4172 // inside the light box
4173 // TODO: check if the surfaces in the model can receive light
4174 // so now check if it's in a leaf seen by the light
4175 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))
4177 if (ent->flags & RENDER_NOSELFSHADOW)
4178 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4180 lightentities[numlightentities++] = ent;
4181 // since it is lit, it probably also casts a shadow...
4182 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4183 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4184 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4186 // note: exterior models without the RENDER_NOSELFSHADOW
4187 // flag still create a RENDER_NOSELFSHADOW shadow but
4188 // are lit normally, this means that they are
4189 // self-shadowing but do not shadow other
4190 // RENDER_NOSELFSHADOW entities such as the gun
4191 // (very weird, but keeps the player shadow off the gun)
4192 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4193 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4195 shadowentities[numshadowentities++] = ent;
4198 else if (ent->flags & RENDER_SHADOW)
4200 // this entity is not receiving light, but may still need to
4202 // TODO: check if the surfaces in the model can cast shadow
4203 // now check if it is in a leaf seen by the light
4204 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))
4206 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4207 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4208 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4210 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4211 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4213 shadowentities[numshadowentities++] = ent;
4219 // return if there's nothing at all to light
4220 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4223 // don't let sound skip if going slow
4224 if (r_refdef.scene.extraupdate)
4227 // make this the active rtlight for rendering purposes
4228 R_Shadow_RenderMode_ActiveLight(rtlight);
4229 // count this light in the r_speeds
4230 r_refdef.stats.lights++;
4232 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4234 // optionally draw visible shape of the shadow volumes
4235 // for performance analysis by level designers
4236 R_Shadow_RenderMode_VisibleShadowVolumes();
4238 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4239 for (i = 0;i < numshadowentities;i++)
4240 R_Shadow_DrawEntityShadow(shadowentities[i]);
4241 for (i = 0;i < numshadowentities_noselfshadow;i++)
4242 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4245 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4247 // optionally draw the illuminated areas
4248 // for performance analysis by level designers
4249 R_Shadow_RenderMode_VisibleLighting(false, false);
4251 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4252 for (i = 0;i < numlightentities;i++)
4253 R_Shadow_DrawEntityLight(lightentities[i]);
4254 for (i = 0;i < numlightentities_noselfshadow;i++)
4255 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4258 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4260 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4261 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4262 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4263 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4265 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4266 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4267 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4269 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4275 int receivermask = 0;
4276 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4277 Matrix4x4_Abs(&radiustolight);
4279 r_shadow_shadowmaplod = 0;
4280 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4281 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4282 r_shadow_shadowmaplod = i;
4284 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
4285 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
4287 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4289 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4293 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4295 castermask = rtlight->static_shadowmap_casters;
4296 receivermask = rtlight->static_shadowmap_receivers;
4300 for(i = 0;i < numsurfaces;i++)
4302 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4303 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4304 castermask |= surfacesides[i];
4305 receivermask |= surfacesides[i];
4309 if (receivermask < 0x3F)
4311 for (i = 0;i < numlightentities;i++)
4312 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4313 if (receivermask < 0x3F)
4314 for(i = 0; i < numlightentities_noselfshadow;i++)
4315 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4318 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4322 for (i = 0;i < numshadowentities;i++)
4323 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4324 for (i = 0;i < numshadowentities_noselfshadow;i++)
4325 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4328 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4330 // render shadow casters into 6 sided depth texture
4331 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4333 R_Shadow_RenderMode_ShadowMap(side, true, size);
4334 if (! (castermask & (1 << side))) continue;
4336 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4337 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4338 R_Shadow_DrawEntityShadow(shadowentities[i]);
4341 if (numlightentities_noselfshadow)
4343 // render lighting using the depth texture as shadowmap
4344 // draw lighting in the unmasked areas
4345 R_Shadow_RenderMode_Lighting(false, false, true);
4346 for (i = 0;i < numlightentities_noselfshadow;i++)
4347 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4350 // render shadow casters into 6 sided depth texture
4351 if (numshadowentities_noselfshadow)
4353 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4355 R_Shadow_RenderMode_ShadowMap(side, false, size);
4356 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4357 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4361 // render lighting using the depth texture as shadowmap
4362 // draw lighting in the unmasked areas
4363 R_Shadow_RenderMode_Lighting(false, false, true);
4364 // draw lighting in the unmasked areas
4366 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4367 for (i = 0;i < numlightentities;i++)
4368 R_Shadow_DrawEntityLight(lightentities[i]);
4370 else if (castshadows && vid.stencil)
4372 // draw stencil shadow volumes to mask off pixels that are in shadow
4373 // so that they won't receive lighting
4374 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4375 R_Shadow_ClearStencil();
4377 if (numsurfaces + numshadowentities)
4380 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4381 for (i = 0;i < numshadowentities;i++)
4382 R_Shadow_DrawEntityShadow(shadowentities[i]);
4385 if (numlightentities_noselfshadow)
4387 // draw lighting in the unmasked areas
4388 R_Shadow_RenderMode_Lighting(true, false, false);
4389 for (i = 0;i < numlightentities_noselfshadow;i++)
4390 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4392 // optionally draw the illuminated areas
4393 // for performance analysis by level designers
4394 if (r_showlighting.integer && r_refdef.view.showdebug)
4396 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4397 for (i = 0;i < numlightentities_noselfshadow;i++)
4398 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4400 for (i = 0;i < numshadowentities_noselfshadow;i++)
4401 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4404 if (numsurfaces + numlightentities)
4406 // draw lighting in the unmasked areas
4407 R_Shadow_RenderMode_Lighting(true, false, false);
4409 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4410 for (i = 0;i < numlightentities;i++)
4411 R_Shadow_DrawEntityLight(lightentities[i]);
4416 // draw lighting in the unmasked areas
4417 R_Shadow_RenderMode_Lighting(false, false, false);
4419 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4420 for (i = 0;i < numlightentities;i++)
4421 R_Shadow_DrawEntityLight(lightentities[i]);
4422 for (i = 0;i < numlightentities_noselfshadow;i++)
4423 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4427 void R_Shadow_DrawLightSprites(void);
4428 void R_ShadowVolumeLighting(qboolean visible)
4437 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4438 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != r_shadow_shadowmapping.integer ||
4439 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4440 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4441 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4442 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4443 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4444 R_Shadow_FreeShadowMaps();
4446 if (r_editlights.integer)
4447 R_Shadow_DrawLightSprites();
4449 R_Shadow_RenderMode_Begin();
4451 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4452 if (r_shadow_debuglight.integer >= 0)
4454 lightindex = r_shadow_debuglight.integer;
4455 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4456 if (light && (light->flags & flag))
4457 R_DrawRTLight(&light->rtlight, visible);
4461 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4462 for (lightindex = 0;lightindex < range;lightindex++)
4464 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4465 if (light && (light->flags & flag))
4466 R_DrawRTLight(&light->rtlight, visible);
4469 if (r_refdef.scene.rtdlight)
4471 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4472 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4474 else if(gl_flashblend.integer)
4476 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4478 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4479 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4480 VectorScale(rtlight->color, f, rtlight->currentcolor);
4484 R_Shadow_RenderMode_End();
4487 extern const float r_screenvertex3f[12];
4488 extern void R_SetupView(qboolean allowwaterclippingplane);
4489 extern void R_ResetViewRendering3D(void);
4490 extern void R_ResetViewRendering2D(void);
4491 extern cvar_t r_shadows;
4492 extern cvar_t r_shadows_darken;
4493 extern cvar_t r_shadows_drawafterrtlighting;
4494 extern cvar_t r_shadows_castfrombmodels;
4495 extern cvar_t r_shadows_throwdistance;
4496 extern cvar_t r_shadows_throwdirection;
4497 void R_DrawModelShadows(void)
4500 float relativethrowdistance;
4501 entity_render_t *ent;
4502 vec3_t relativelightorigin;
4503 vec3_t relativelightdirection;
4504 vec3_t relativeshadowmins, relativeshadowmaxs;
4505 vec3_t tmp, shadowdir;
4507 if (!r_drawentities.integer || !vid.stencil)
4511 R_ResetViewRendering3D();
4512 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4513 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4514 R_Shadow_RenderMode_Begin();
4515 R_Shadow_RenderMode_ActiveLight(NULL);
4516 r_shadow_lightscissor[0] = r_refdef.view.x;
4517 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4518 r_shadow_lightscissor[2] = r_refdef.view.width;
4519 r_shadow_lightscissor[3] = r_refdef.view.height;
4520 R_Shadow_RenderMode_StencilShadowVolumes(false);
4523 if (r_shadows.integer == 2)
4525 Math_atov(r_shadows_throwdirection.string, shadowdir);
4526 VectorNormalize(shadowdir);
4529 R_Shadow_ClearStencil();
4531 for (i = 0;i < r_refdef.scene.numentities;i++)
4533 ent = r_refdef.scene.entities[i];
4535 // cast shadows from anything of the map (submodels are optional)
4536 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4538 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4539 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4540 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4541 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4542 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4545 if(ent->entitynumber != 0)
4547 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4548 int entnum, entnum2, recursion;
4549 entnum = entnum2 = ent->entitynumber;
4550 for(recursion = 32; recursion > 0; --recursion)
4552 entnum2 = cl.entities[entnum].state_current.tagentity;
4553 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4558 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4560 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4561 // transform into modelspace of OUR entity
4562 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4563 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4566 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4569 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4572 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4573 RSurf_ActiveModelEntity(ent, false, false);
4574 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4575 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4579 // not really the right mode, but this will disable any silly stencil features
4580 R_Shadow_RenderMode_End();
4582 // set up ortho view for rendering this pass
4583 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4584 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4585 //GL_ScissorTest(true);
4586 //R_Mesh_Matrix(&identitymatrix);
4587 //R_Mesh_ResetTextureState();
4588 R_ResetViewRendering2D();
4589 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4590 R_Mesh_ColorPointer(NULL, 0, 0);
4591 R_SetupGenericShader(false);
4593 // set up a darkening blend on shadowed areas
4594 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4595 //GL_DepthRange(0, 1);
4596 //GL_DepthTest(false);
4597 //GL_DepthMask(false);
4598 //GL_PolygonOffset(0, 0);CHECKGLERROR
4599 GL_Color(0, 0, 0, r_shadows_darken.value);
4600 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4601 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4602 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4603 qglStencilMask(~0);CHECKGLERROR
4604 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4605 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4607 // apply the blend to the shadowed areas
4608 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4610 // restore the viewport
4611 R_SetViewport(&r_refdef.view.viewport);
4613 // restore other state to normal
4614 //R_Shadow_RenderMode_End();
4617 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4620 vec3_t centerorigin;
4622 // if it's too close, skip it
4623 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4625 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4628 if (usequery && r_numqueries + 2 <= r_maxqueries)
4630 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4631 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4632 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4633 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4636 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4637 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4638 qglDepthFunc(GL_ALWAYS);
4639 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4640 R_Mesh_VertexPointer(vertex3f, 0, 0);
4641 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4642 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4643 qglDepthFunc(GL_LEQUAL);
4644 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4645 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4646 R_Mesh_VertexPointer(vertex3f, 0, 0);
4647 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4648 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4651 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4654 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4656 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4659 GLint allpixels = 0, visiblepixels = 0;
4660 // now we have to check the query result
4661 if (rtlight->corona_queryindex_visiblepixels)
4664 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4665 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4667 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4668 if (visiblepixels < 1 || allpixels < 1)
4670 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4671 cscale *= rtlight->corona_visibility;
4675 // FIXME: these traces should scan all render entities instead of cl.world
4676 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4679 VectorScale(rtlight->currentcolor, cscale, color);
4680 if (VectorLength(color) > (1.0f / 256.0f))
4683 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4686 VectorNegate(color, color);
4687 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4689 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4690 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4691 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4693 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4697 void R_DrawCoronas(void)
4705 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4707 if (r_waterstate.renderingscene)
4709 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4710 R_Mesh_Matrix(&identitymatrix);
4712 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4714 // check occlusion of coronas
4715 // use GL_ARB_occlusion_query if available
4716 // otherwise use raytraces
4718 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4721 GL_ColorMask(0,0,0,0);
4722 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4723 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4726 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4727 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4729 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4732 RSurf_ActiveWorldEntity();
4733 GL_BlendFunc(GL_ONE, GL_ZERO);
4734 GL_CullFace(GL_NONE);
4735 GL_DepthMask(false);
4736 GL_DepthRange(0, 1);
4737 GL_PolygonOffset(0, 0);
4739 R_Mesh_ColorPointer(NULL, 0, 0);
4740 R_Mesh_ResetTextureState();
4741 R_SetupGenericShader(false);
4743 for (lightindex = 0;lightindex < range;lightindex++)
4745 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4748 rtlight = &light->rtlight;
4749 rtlight->corona_visibility = 0;
4750 rtlight->corona_queryindex_visiblepixels = 0;
4751 rtlight->corona_queryindex_allpixels = 0;
4752 if (!(rtlight->flags & flag))
4754 if (rtlight->corona <= 0)
4756 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4758 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4760 for (i = 0;i < r_refdef.scene.numlights;i++)
4762 rtlight = r_refdef.scene.lights[i];
4763 rtlight->corona_visibility = 0;
4764 rtlight->corona_queryindex_visiblepixels = 0;
4765 rtlight->corona_queryindex_allpixels = 0;
4766 if (!(rtlight->flags & flag))
4768 if (rtlight->corona <= 0)
4770 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4773 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4775 // now draw the coronas using the query data for intensity info
4776 for (lightindex = 0;lightindex < range;lightindex++)
4778 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4781 rtlight = &light->rtlight;
4782 if (rtlight->corona_visibility <= 0)
4784 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4786 for (i = 0;i < r_refdef.scene.numlights;i++)
4788 rtlight = r_refdef.scene.lights[i];
4789 if (rtlight->corona_visibility <= 0)
4791 if (gl_flashblend.integer)
4792 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4794 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4800 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4801 typedef struct suffixinfo_s
4804 qboolean flipx, flipy, flipdiagonal;
4807 static suffixinfo_t suffix[3][6] =
4810 {"px", false, false, false},
4811 {"nx", false, false, false},
4812 {"py", false, false, false},
4813 {"ny", false, false, false},
4814 {"pz", false, false, false},
4815 {"nz", false, false, false}
4818 {"posx", false, false, false},
4819 {"negx", false, false, false},
4820 {"posy", false, false, false},
4821 {"negy", false, false, false},
4822 {"posz", false, false, false},
4823 {"negz", false, false, false}
4826 {"rt", true, false, true},
4827 {"lf", false, true, true},
4828 {"ft", true, true, false},
4829 {"bk", false, false, false},
4830 {"up", true, false, true},
4831 {"dn", true, false, true}
4835 static int componentorder[4] = {0, 1, 2, 3};
4837 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4839 int i, j, cubemapsize;
4840 unsigned char *cubemappixels, *image_buffer;
4841 rtexture_t *cubemaptexture;
4843 // must start 0 so the first loadimagepixels has no requested width/height
4845 cubemappixels = NULL;
4846 cubemaptexture = NULL;
4847 // keep trying different suffix groups (posx, px, rt) until one loads
4848 for (j = 0;j < 3 && !cubemappixels;j++)
4850 // load the 6 images in the suffix group
4851 for (i = 0;i < 6;i++)
4853 // generate an image name based on the base and and suffix
4854 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4856 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4858 // an image loaded, make sure width and height are equal
4859 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4861 // if this is the first image to load successfully, allocate the cubemap memory
4862 if (!cubemappixels && image_width >= 1)
4864 cubemapsize = image_width;
4865 // note this clears to black, so unavailable sides are black
4866 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4868 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4870 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);
4873 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4875 Mem_Free(image_buffer);
4879 // if a cubemap loaded, upload it
4882 if (developer_loading.integer)
4883 Con_Printf("loading cubemap \"%s\"\n", basename);
4885 if (!r_shadow_filters_texturepool)
4886 r_shadow_filters_texturepool = R_AllocTexturePool();
4887 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4888 Mem_Free(cubemappixels);
4892 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4893 if (developer_loading.integer)
4895 Con_Printf("(tried tried images ");
4896 for (j = 0;j < 3;j++)
4897 for (i = 0;i < 6;i++)
4898 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4899 Con_Print(" and was unable to find any of them).\n");
4902 return cubemaptexture;
4905 rtexture_t *R_Shadow_Cubemap(const char *basename)
4908 for (i = 0;i < numcubemaps;i++)
4909 if (!strcasecmp(cubemaps[i].basename, basename))
4910 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4911 if (i >= MAX_CUBEMAPS)
4912 return r_texture_whitecube;
4914 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4915 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4916 return cubemaps[i].texture;
4919 void R_Shadow_FreeCubemaps(void)
4922 for (i = 0;i < numcubemaps;i++)
4924 if (developer_loading.integer)
4925 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4926 if (cubemaps[i].texture)
4927 R_FreeTexture(cubemaps[i].texture);
4931 R_FreeTexturePool(&r_shadow_filters_texturepool);
4934 dlight_t *R_Shadow_NewWorldLight(void)
4936 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4939 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)
4942 // validate parameters
4943 if (style < 0 || style >= MAX_LIGHTSTYLES)
4945 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4951 // copy to light properties
4952 VectorCopy(origin, light->origin);
4953 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4954 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4955 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4957 light->color[0] = max(color[0], 0);
4958 light->color[1] = max(color[1], 0);
4959 light->color[2] = max(color[2], 0);
4961 light->color[0] = color[0];
4962 light->color[1] = color[1];
4963 light->color[2] = color[2];
4964 light->radius = max(radius, 0);
4965 light->style = style;
4966 light->shadow = shadowenable;
4967 light->corona = corona;
4968 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4969 light->coronasizescale = coronasizescale;
4970 light->ambientscale = ambientscale;
4971 light->diffusescale = diffusescale;
4972 light->specularscale = specularscale;
4973 light->flags = flags;
4975 // update renderable light data
4976 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4977 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);
4980 void R_Shadow_FreeWorldLight(dlight_t *light)
4982 if (r_shadow_selectedlight == light)
4983 r_shadow_selectedlight = NULL;
4984 R_RTLight_Uncompile(&light->rtlight);
4985 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4988 void R_Shadow_ClearWorldLights(void)
4992 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4993 for (lightindex = 0;lightindex < range;lightindex++)
4995 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4997 R_Shadow_FreeWorldLight(light);
4999 r_shadow_selectedlight = NULL;
5000 R_Shadow_FreeCubemaps();
5003 void R_Shadow_SelectLight(dlight_t *light)
5005 if (r_shadow_selectedlight)
5006 r_shadow_selectedlight->selected = false;
5007 r_shadow_selectedlight = light;
5008 if (r_shadow_selectedlight)
5009 r_shadow_selectedlight->selected = true;
5012 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5014 // this is never batched (there can be only one)
5016 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5017 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5018 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5021 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5026 skinframe_t *skinframe;
5029 // this is never batched (due to the ent parameter changing every time)
5030 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5031 const dlight_t *light = (dlight_t *)ent;
5034 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5037 VectorScale(light->color, intensity, spritecolor);
5038 if (VectorLength(spritecolor) < 0.1732f)
5039 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5040 if (VectorLength(spritecolor) > 1.0f)
5041 VectorNormalize(spritecolor);
5043 // draw light sprite
5044 if (light->cubemapname[0] && !light->shadow)
5045 skinframe = r_editlights_sprcubemapnoshadowlight;
5046 else if (light->cubemapname[0])
5047 skinframe = r_editlights_sprcubemaplight;
5048 else if (!light->shadow)
5049 skinframe = r_editlights_sprnoshadowlight;
5051 skinframe = r_editlights_sprlight;
5053 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5054 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5056 // draw selection sprite if light is selected
5057 if (light->selected)
5059 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5060 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5061 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5065 void R_Shadow_DrawLightSprites(void)
5069 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5070 for (lightindex = 0;lightindex < range;lightindex++)
5072 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5074 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5076 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5079 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5084 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5085 if (lightindex >= range)
5087 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5090 rtlight = &light->rtlight;
5091 //if (!(rtlight->flags & flag))
5093 VectorCopy(rtlight->shadoworigin, origin);
5094 *radius = rtlight->radius;
5095 VectorCopy(rtlight->color, color);
5099 void R_Shadow_SelectLightInView(void)
5101 float bestrating, rating, temp[3];
5105 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5108 for (lightindex = 0;lightindex < range;lightindex++)
5110 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5113 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5114 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5117 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5118 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5120 bestrating = rating;
5125 R_Shadow_SelectLight(best);
5128 void R_Shadow_LoadWorldLights(void)
5130 int n, a, style, shadow, flags;
5131 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5132 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5133 if (cl.worldmodel == NULL)
5135 Con_Print("No map loaded.\n");
5138 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5139 strlcat (name, ".rtlights", sizeof (name));
5140 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5150 for (;COM_Parse(t, true) && strcmp(
5151 if (COM_Parse(t, true))
5153 if (com_token[0] == '!')
5156 origin[0] = atof(com_token+1);
5159 origin[0] = atof(com_token);
5164 while (*s && *s != '\n' && *s != '\r')
5170 // check for modifier flags
5177 #if _MSC_VER >= 1400
5178 #define sscanf sscanf_s
5180 cubemapname[sizeof(cubemapname)-1] = 0;
5181 #if MAX_QPATH != 128
5182 #error update this code if MAX_QPATH changes
5184 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
5185 #if _MSC_VER >= 1400
5186 , sizeof(cubemapname)
5188 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5191 flags = LIGHTFLAG_REALTIMEMODE;
5199 coronasizescale = 0.25f;
5201 VectorClear(angles);
5204 if (a < 9 || !strcmp(cubemapname, "\"\""))
5206 // remove quotes on cubemapname
5207 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5210 namelen = strlen(cubemapname) - 2;
5211 memmove(cubemapname, cubemapname + 1, namelen);
5212 cubemapname[namelen] = '\0';
5216 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);
5219 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5227 Con_Printf("invalid rtlights file \"%s\"\n", name);
5228 Mem_Free(lightsstring);
5232 void R_Shadow_SaveWorldLights(void)
5236 size_t bufchars, bufmaxchars;
5238 char name[MAX_QPATH];
5239 char line[MAX_INPUTLINE];
5240 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5241 // I hate lines which are 3 times my screen size :( --blub
5244 if (cl.worldmodel == NULL)
5246 Con_Print("No map loaded.\n");
5249 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5250 strlcat (name, ".rtlights", sizeof (name));
5251 bufchars = bufmaxchars = 0;
5253 for (lightindex = 0;lightindex < range;lightindex++)
5255 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5258 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5259 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);
5260 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5261 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]);
5263 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);
5264 if (bufchars + strlen(line) > bufmaxchars)
5266 bufmaxchars = bufchars + strlen(line) + 2048;
5268 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5272 memcpy(buf, oldbuf, bufchars);
5278 memcpy(buf + bufchars, line, strlen(line));
5279 bufchars += strlen(line);
5283 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5288 void R_Shadow_LoadLightsFile(void)
5291 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5292 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5293 if (cl.worldmodel == NULL)
5295 Con_Print("No map loaded.\n");
5298 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5299 strlcat (name, ".lights", sizeof (name));
5300 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5308 while (*s && *s != '\n' && *s != '\r')
5314 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);
5318 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);
5321 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5322 radius = bound(15, radius, 4096);
5323 VectorScale(color, (2.0f / (8388608.0f)), color);
5324 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5332 Con_Printf("invalid lights file \"%s\"\n", name);
5333 Mem_Free(lightsstring);
5337 // tyrlite/hmap2 light types in the delay field
5338 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5340 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5342 int entnum, style, islight, skin, pflags, effects, type, n;
5345 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5346 char key[256], value[MAX_INPUTLINE];
5348 if (cl.worldmodel == NULL)
5350 Con_Print("No map loaded.\n");
5353 // try to load a .ent file first
5354 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5355 strlcat (key, ".ent", sizeof (key));
5356 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5357 // and if that is not found, fall back to the bsp file entity string
5359 data = cl.worldmodel->brush.entities;
5362 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5364 type = LIGHTTYPE_MINUSX;
5365 origin[0] = origin[1] = origin[2] = 0;
5366 originhack[0] = originhack[1] = originhack[2] = 0;
5367 angles[0] = angles[1] = angles[2] = 0;
5368 color[0] = color[1] = color[2] = 1;
5369 light[0] = light[1] = light[2] = 1;light[3] = 300;
5370 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5380 if (!COM_ParseToken_Simple(&data, false, false))
5382 if (com_token[0] == '}')
5383 break; // end of entity
5384 if (com_token[0] == '_')
5385 strlcpy(key, com_token + 1, sizeof(key));
5387 strlcpy(key, com_token, sizeof(key));
5388 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5389 key[strlen(key)-1] = 0;
5390 if (!COM_ParseToken_Simple(&data, false, false))
5392 strlcpy(value, com_token, sizeof(value));
5394 // now that we have the key pair worked out...
5395 if (!strcmp("light", key))
5397 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5401 light[0] = vec[0] * (1.0f / 256.0f);
5402 light[1] = vec[0] * (1.0f / 256.0f);
5403 light[2] = vec[0] * (1.0f / 256.0f);
5409 light[0] = vec[0] * (1.0f / 255.0f);
5410 light[1] = vec[1] * (1.0f / 255.0f);
5411 light[2] = vec[2] * (1.0f / 255.0f);
5415 else if (!strcmp("delay", key))
5417 else if (!strcmp("origin", key))
5418 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5419 else if (!strcmp("angle", key))
5420 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5421 else if (!strcmp("angles", key))
5422 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5423 else if (!strcmp("color", key))
5424 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5425 else if (!strcmp("wait", key))
5426 fadescale = atof(value);
5427 else if (!strcmp("classname", key))
5429 if (!strncmp(value, "light", 5))
5432 if (!strcmp(value, "light_fluoro"))
5437 overridecolor[0] = 1;
5438 overridecolor[1] = 1;
5439 overridecolor[2] = 1;
5441 if (!strcmp(value, "light_fluorospark"))
5446 overridecolor[0] = 1;
5447 overridecolor[1] = 1;
5448 overridecolor[2] = 1;
5450 if (!strcmp(value, "light_globe"))
5455 overridecolor[0] = 1;
5456 overridecolor[1] = 0.8;
5457 overridecolor[2] = 0.4;
5459 if (!strcmp(value, "light_flame_large_yellow"))
5464 overridecolor[0] = 1;
5465 overridecolor[1] = 0.5;
5466 overridecolor[2] = 0.1;
5468 if (!strcmp(value, "light_flame_small_yellow"))
5473 overridecolor[0] = 1;
5474 overridecolor[1] = 0.5;
5475 overridecolor[2] = 0.1;
5477 if (!strcmp(value, "light_torch_small_white"))
5482 overridecolor[0] = 1;
5483 overridecolor[1] = 0.5;
5484 overridecolor[2] = 0.1;
5486 if (!strcmp(value, "light_torch_small_walltorch"))
5491 overridecolor[0] = 1;
5492 overridecolor[1] = 0.5;
5493 overridecolor[2] = 0.1;
5497 else if (!strcmp("style", key))
5498 style = atoi(value);
5499 else if (!strcmp("skin", key))
5500 skin = (int)atof(value);
5501 else if (!strcmp("pflags", key))
5502 pflags = (int)atof(value);
5503 else if (!strcmp("effects", key))
5504 effects = (int)atof(value);
5505 else if (cl.worldmodel->type == mod_brushq3)
5507 if (!strcmp("scale", key))
5508 lightscale = atof(value);
5509 if (!strcmp("fade", key))
5510 fadescale = atof(value);
5515 if (lightscale <= 0)
5519 if (color[0] == color[1] && color[0] == color[2])
5521 color[0] *= overridecolor[0];
5522 color[1] *= overridecolor[1];
5523 color[2] *= overridecolor[2];
5525 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5526 color[0] = color[0] * light[0];
5527 color[1] = color[1] * light[1];
5528 color[2] = color[2] * light[2];
5531 case LIGHTTYPE_MINUSX:
5533 case LIGHTTYPE_RECIPX:
5535 VectorScale(color, (1.0f / 16.0f), color);
5537 case LIGHTTYPE_RECIPXX:
5539 VectorScale(color, (1.0f / 16.0f), color);
5542 case LIGHTTYPE_NONE:
5546 case LIGHTTYPE_MINUSXX:
5549 VectorAdd(origin, originhack, origin);
5551 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);
5554 Mem_Free(entfiledata);
5558 void R_Shadow_SetCursorLocationForView(void)
5561 vec3_t dest, endpos;
5563 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5564 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5565 if (trace.fraction < 1)
5567 dist = trace.fraction * r_editlights_cursordistance.value;
5568 push = r_editlights_cursorpushback.value;
5572 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5573 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5577 VectorClear( endpos );
5579 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5580 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5581 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5584 void R_Shadow_UpdateWorldLightSelection(void)
5586 if (r_editlights.integer)
5588 R_Shadow_SetCursorLocationForView();
5589 R_Shadow_SelectLightInView();
5592 R_Shadow_SelectLight(NULL);
5595 void R_Shadow_EditLights_Clear_f(void)
5597 R_Shadow_ClearWorldLights();
5600 void R_Shadow_EditLights_Reload_f(void)
5604 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5605 R_Shadow_ClearWorldLights();
5606 R_Shadow_LoadWorldLights();
5607 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5609 R_Shadow_LoadLightsFile();
5610 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5611 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5615 void R_Shadow_EditLights_Save_f(void)
5619 R_Shadow_SaveWorldLights();
5622 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5624 R_Shadow_ClearWorldLights();
5625 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5628 void R_Shadow_EditLights_ImportLightsFile_f(void)
5630 R_Shadow_ClearWorldLights();
5631 R_Shadow_LoadLightsFile();
5634 void R_Shadow_EditLights_Spawn_f(void)
5637 if (!r_editlights.integer)
5639 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5642 if (Cmd_Argc() != 1)
5644 Con_Print("r_editlights_spawn does not take parameters\n");
5647 color[0] = color[1] = color[2] = 1;
5648 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5651 void R_Shadow_EditLights_Edit_f(void)
5653 vec3_t origin, angles, color;
5654 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5655 int style, shadows, flags, normalmode, realtimemode;
5656 char cubemapname[MAX_INPUTLINE];
5657 if (!r_editlights.integer)
5659 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5662 if (!r_shadow_selectedlight)
5664 Con_Print("No selected light.\n");
5667 VectorCopy(r_shadow_selectedlight->origin, origin);
5668 VectorCopy(r_shadow_selectedlight->angles, angles);
5669 VectorCopy(r_shadow_selectedlight->color, color);
5670 radius = r_shadow_selectedlight->radius;
5671 style = r_shadow_selectedlight->style;
5672 if (r_shadow_selectedlight->cubemapname)
5673 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5676 shadows = r_shadow_selectedlight->shadow;
5677 corona = r_shadow_selectedlight->corona;
5678 coronasizescale = r_shadow_selectedlight->coronasizescale;
5679 ambientscale = r_shadow_selectedlight->ambientscale;
5680 diffusescale = r_shadow_selectedlight->diffusescale;
5681 specularscale = r_shadow_selectedlight->specularscale;
5682 flags = r_shadow_selectedlight->flags;
5683 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5684 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5685 if (!strcmp(Cmd_Argv(1), "origin"))
5687 if (Cmd_Argc() != 5)
5689 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5692 origin[0] = atof(Cmd_Argv(2));
5693 origin[1] = atof(Cmd_Argv(3));
5694 origin[2] = atof(Cmd_Argv(4));
5696 else if (!strcmp(Cmd_Argv(1), "originx"))
5698 if (Cmd_Argc() != 3)
5700 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5703 origin[0] = atof(Cmd_Argv(2));
5705 else if (!strcmp(Cmd_Argv(1), "originy"))
5707 if (Cmd_Argc() != 3)
5709 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5712 origin[1] = atof(Cmd_Argv(2));
5714 else if (!strcmp(Cmd_Argv(1), "originz"))
5716 if (Cmd_Argc() != 3)
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 origin[2] = atof(Cmd_Argv(2));
5723 else if (!strcmp(Cmd_Argv(1), "move"))
5725 if (Cmd_Argc() != 5)
5727 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5730 origin[0] += atof(Cmd_Argv(2));
5731 origin[1] += atof(Cmd_Argv(3));
5732 origin[2] += atof(Cmd_Argv(4));
5734 else if (!strcmp(Cmd_Argv(1), "movex"))
5736 if (Cmd_Argc() != 3)
5738 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5741 origin[0] += atof(Cmd_Argv(2));
5743 else if (!strcmp(Cmd_Argv(1), "movey"))
5745 if (Cmd_Argc() != 3)
5747 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5750 origin[1] += atof(Cmd_Argv(2));
5752 else if (!strcmp(Cmd_Argv(1), "movez"))
5754 if (Cmd_Argc() != 3)
5756 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5759 origin[2] += atof(Cmd_Argv(2));
5761 else if (!strcmp(Cmd_Argv(1), "angles"))
5763 if (Cmd_Argc() != 5)
5765 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5768 angles[0] = atof(Cmd_Argv(2));
5769 angles[1] = atof(Cmd_Argv(3));
5770 angles[2] = atof(Cmd_Argv(4));
5772 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5774 if (Cmd_Argc() != 3)
5776 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5779 angles[0] = atof(Cmd_Argv(2));
5781 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5783 if (Cmd_Argc() != 3)
5785 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5788 angles[1] = atof(Cmd_Argv(2));
5790 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5792 if (Cmd_Argc() != 3)
5794 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5797 angles[2] = atof(Cmd_Argv(2));
5799 else if (!strcmp(Cmd_Argv(1), "color"))
5801 if (Cmd_Argc() != 5)
5803 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5806 color[0] = atof(Cmd_Argv(2));
5807 color[1] = atof(Cmd_Argv(3));
5808 color[2] = atof(Cmd_Argv(4));
5810 else if (!strcmp(Cmd_Argv(1), "radius"))
5812 if (Cmd_Argc() != 3)
5814 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5817 radius = atof(Cmd_Argv(2));
5819 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5821 if (Cmd_Argc() == 3)
5823 double scale = atof(Cmd_Argv(2));
5830 if (Cmd_Argc() != 5)
5832 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5835 color[0] *= atof(Cmd_Argv(2));
5836 color[1] *= atof(Cmd_Argv(3));
5837 color[2] *= atof(Cmd_Argv(4));
5840 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5842 if (Cmd_Argc() != 3)
5844 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5847 radius *= atof(Cmd_Argv(2));
5849 else if (!strcmp(Cmd_Argv(1), "style"))
5851 if (Cmd_Argc() != 3)
5853 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5856 style = atoi(Cmd_Argv(2));
5858 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5862 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5865 if (Cmd_Argc() == 3)
5866 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5870 else if (!strcmp(Cmd_Argv(1), "shadows"))
5872 if (Cmd_Argc() != 3)
5874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5877 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5879 else if (!strcmp(Cmd_Argv(1), "corona"))
5881 if (Cmd_Argc() != 3)
5883 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5886 corona = atof(Cmd_Argv(2));
5888 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5890 if (Cmd_Argc() != 3)
5892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5895 coronasizescale = atof(Cmd_Argv(2));
5897 else if (!strcmp(Cmd_Argv(1), "ambient"))
5899 if (Cmd_Argc() != 3)
5901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5904 ambientscale = atof(Cmd_Argv(2));
5906 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5908 if (Cmd_Argc() != 3)
5910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5913 diffusescale = atof(Cmd_Argv(2));
5915 else if (!strcmp(Cmd_Argv(1), "specular"))
5917 if (Cmd_Argc() != 3)
5919 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5922 specularscale = atof(Cmd_Argv(2));
5924 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5926 if (Cmd_Argc() != 3)
5928 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5931 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5933 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5935 if (Cmd_Argc() != 3)
5937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5940 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5944 Con_Print("usage: r_editlights_edit [property] [value]\n");
5945 Con_Print("Selected light's properties:\n");
5946 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5947 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5948 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5949 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5950 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5951 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5952 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5953 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5954 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5955 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5956 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5957 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5958 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5959 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5962 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5963 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5966 void R_Shadow_EditLights_EditAll_f(void)
5972 if (!r_editlights.integer)
5974 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5978 // EditLights doesn't seem to have a "remove" command or something so:
5979 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5980 for (lightindex = 0;lightindex < range;lightindex++)
5982 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5985 R_Shadow_SelectLight(light);
5986 R_Shadow_EditLights_Edit_f();
5990 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5992 int lightnumber, lightcount;
5993 size_t lightindex, range;
5997 if (!r_editlights.integer)
5999 x = vid_conwidth.value - 240;
6001 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6004 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6005 for (lightindex = 0;lightindex < range;lightindex++)
6007 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6010 if (light == r_shadow_selectedlight)
6011 lightnumber = lightindex;
6014 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;
6015 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;
6017 if (r_shadow_selectedlight == NULL)
6019 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;
6020 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;
6021 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;
6022 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;
6023 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;
6024 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;
6025 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;
6026 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;
6027 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;
6028 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;
6029 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;
6030 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;
6031 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;
6032 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;
6033 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;
6036 void R_Shadow_EditLights_ToggleShadow_f(void)
6038 if (!r_editlights.integer)
6040 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6043 if (!r_shadow_selectedlight)
6045 Con_Print("No selected light.\n");
6048 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);
6051 void R_Shadow_EditLights_ToggleCorona_f(void)
6053 if (!r_editlights.integer)
6055 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6058 if (!r_shadow_selectedlight)
6060 Con_Print("No selected light.\n");
6063 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);
6066 void R_Shadow_EditLights_Remove_f(void)
6068 if (!r_editlights.integer)
6070 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6073 if (!r_shadow_selectedlight)
6075 Con_Print("No selected light.\n");
6078 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6079 r_shadow_selectedlight = NULL;
6082 void R_Shadow_EditLights_Help_f(void)
6085 "Documentation on r_editlights system:\n"
6087 "r_editlights : enable/disable editing mode\n"
6088 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6089 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6090 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6091 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6092 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6094 "r_editlights_help : this help\n"
6095 "r_editlights_clear : remove all lights\n"
6096 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6097 "r_editlights_save : save to .rtlights file\n"
6098 "r_editlights_spawn : create a light with default settings\n"
6099 "r_editlights_edit command : edit selected light - more documentation below\n"
6100 "r_editlights_remove : remove selected light\n"
6101 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6102 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6103 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6105 "origin x y z : set light location\n"
6106 "originx x: set x component of light location\n"
6107 "originy y: set y component of light location\n"
6108 "originz z: set z component of light location\n"
6109 "move x y z : adjust light location\n"
6110 "movex x: adjust x component of light location\n"
6111 "movey y: adjust y component of light location\n"
6112 "movez z: adjust z component of light location\n"
6113 "angles x y z : set light angles\n"
6114 "anglesx x: set x component of light angles\n"
6115 "anglesy y: set y component of light angles\n"
6116 "anglesz z: set z component of light angles\n"
6117 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6118 "radius radius : set radius (size) of light\n"
6119 "colorscale grey : multiply color of light (1 does nothing)\n"
6120 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6121 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6122 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6123 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6124 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6125 "shadows 1/0 : turn on/off shadows\n"
6126 "corona n : set corona intensity\n"
6127 "coronasize n : set corona size (0-1)\n"
6128 "ambient n : set ambient intensity (0-1)\n"
6129 "diffuse n : set diffuse intensity (0-1)\n"
6130 "specular n : set specular intensity (0-1)\n"
6131 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6132 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6133 "<nothing> : print light properties to console\n"
6137 void R_Shadow_EditLights_CopyInfo_f(void)
6139 if (!r_editlights.integer)
6141 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6144 if (!r_shadow_selectedlight)
6146 Con_Print("No selected light.\n");
6149 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6150 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6151 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6152 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6153 if (r_shadow_selectedlight->cubemapname)
6154 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6156 r_shadow_bufferlight.cubemapname[0] = 0;
6157 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6158 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6159 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6160 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6161 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6162 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6163 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6166 void R_Shadow_EditLights_PasteInfo_f(void)
6168 if (!r_editlights.integer)
6170 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6173 if (!r_shadow_selectedlight)
6175 Con_Print("No selected light.\n");
6178 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);
6181 void R_Shadow_EditLights_Init(void)
6183 Cvar_RegisterVariable(&r_editlights);
6184 Cvar_RegisterVariable(&r_editlights_cursordistance);
6185 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6186 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6187 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6188 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6189 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6190 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6191 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)");
6192 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6193 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6194 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6195 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)");
6196 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6197 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6198 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6199 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6200 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6201 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6202 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)");
6208 =============================================================================
6212 =============================================================================
6215 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6217 VectorClear(diffusecolor);
6218 VectorClear(diffusenormal);
6220 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6222 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6223 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6226 VectorSet(ambientcolor, 1, 1, 1);
6233 for (i = 0;i < r_refdef.scene.numlights;i++)
6235 light = r_refdef.scene.lights[i];
6236 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6237 f = 1 - VectorLength2(v);
6238 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6239 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);