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_VERTEX2DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
159 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
160 R_SHADOW_RENDERMODE_LIGHT_GLSL,
161 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
162 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
163 R_SHADOW_RENDERMODE_SHADOWMAP2D,
164 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
165 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
167 r_shadow_rendermode_t;
169 typedef enum r_shadow_shadowmode_e
171 R_SHADOW_SHADOWMODE_STENCIL,
172 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
173 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
174 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmaprect;
183 qboolean r_shadow_usingshadowmap2d;
184 qboolean r_shadow_usingshadowmapcube;
185 int r_shadow_shadowmapside;
186 float r_shadow_shadowmap_texturescale[2];
187 float r_shadow_shadowmap_parameters[4];
189 int r_shadow_drawbuffer;
190 int r_shadow_readbuffer;
192 int r_shadow_cullface_front, r_shadow_cullface_back;
193 GLuint r_shadow_fborectangle;
194 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
195 GLuint r_shadow_fbo2d;
196 r_shadow_shadowmode_t r_shadow_shadowmode;
197 int r_shadow_shadowmapfilterquality;
198 int r_shadow_shadowmaptexturetype;
199 int r_shadow_shadowmapdepthbits;
200 int r_shadow_shadowmapmaxsize;
201 qboolean r_shadow_shadowmapvsdct;
202 qboolean r_shadow_shadowmapsampler;
203 int r_shadow_shadowmappcf;
204 int r_shadow_shadowmapborder;
205 int r_shadow_lightscissor[4];
207 int maxshadowtriangles;
210 int maxshadowvertices;
211 float *shadowvertex3f;
221 unsigned char *shadowsides;
222 int *shadowsideslist;
229 int r_shadow_buffer_numleafpvsbytes;
230 unsigned char *r_shadow_buffer_visitingleafpvs;
231 unsigned char *r_shadow_buffer_leafpvs;
232 int *r_shadow_buffer_leaflist;
234 int r_shadow_buffer_numsurfacepvsbytes;
235 unsigned char *r_shadow_buffer_surfacepvs;
236 int *r_shadow_buffer_surfacelist;
237 unsigned char *r_shadow_buffer_surfacesides;
239 int r_shadow_buffer_numshadowtrispvsbytes;
240 unsigned char *r_shadow_buffer_shadowtrispvs;
241 int r_shadow_buffer_numlighttrispvsbytes;
242 unsigned char *r_shadow_buffer_lighttrispvs;
244 rtexturepool_t *r_shadow_texturepool;
245 rtexture_t *r_shadow_attenuationgradienttexture;
246 rtexture_t *r_shadow_attenuation2dtexture;
247 rtexture_t *r_shadow_attenuation3dtexture;
248 skinframe_t *r_shadow_lightcorona;
249 rtexture_t *r_shadow_shadowmaprectangletexture;
250 rtexture_t *r_shadow_shadowmap2dtexture;
251 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
252 rtexture_t *r_shadow_shadowmapvsdcttexture;
253 int r_shadow_shadowmapsize; // changes for each light based on distance
254 int r_shadow_shadowmaplod; // changes for each light based on distance
256 // lights are reloaded when this changes
257 char r_shadow_mapname[MAX_QPATH];
259 // used only for light filters (cubemaps)
260 rtexturepool_t *r_shadow_filters_texturepool;
262 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"};
263 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"};
264 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
265 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
266 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)"};
267 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"};
268 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
269 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
270 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
271 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
272 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
274 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
275 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
276 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
277 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
278 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)"};
279 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
280 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
281 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
282 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
283 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)"};
284 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"};
285 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
286 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
287 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"};
288 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
289 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
290 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)"};
291 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"};
292 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"};
293 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)"};
294 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
295 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
296 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
298 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"};
299 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
300 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
301 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
302 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
303 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
304 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
305 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
306 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
307 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
308 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)"};
309 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
310 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
311 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"};
312 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
313 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
314 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
315 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
316 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
317 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
318 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
319 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
320 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
321 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
323 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
324 #define ATTENTABLESIZE 256
325 // 1D gradient, 2D circle and 3D sphere attenuation textures
326 #define ATTEN1DSIZE 32
327 #define ATTEN2DSIZE 64
328 #define ATTEN3DSIZE 32
330 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
331 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
332 static float r_shadow_attentable[ATTENTABLESIZE+1];
334 rtlight_t *r_shadow_compilingrtlight;
335 static memexpandablearray_t r_shadow_worldlightsarray;
336 dlight_t *r_shadow_selectedlight;
337 dlight_t r_shadow_bufferlight;
338 vec3_t r_editlights_cursorlocation;
340 extern int con_vislines;
342 typedef struct cubemapinfo_s
349 static int numcubemaps;
350 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
362 #define EDLIGHTSPRSIZE 8
363 skinframe_t *r_editlights_sprcursor;
364 skinframe_t *r_editlights_sprlight;
365 skinframe_t *r_editlights_sprnoshadowlight;
366 skinframe_t *r_editlights_sprcubemaplight;
367 skinframe_t *r_editlights_sprcubemapnoshadowlight;
368 skinframe_t *r_editlights_sprselection;
370 void R_Shadow_SetShadowMode(void)
372 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
373 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
374 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
375 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
376 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 switch(vid.renderpath)
385 case RENDERPATH_GL20:
386 if(r_shadow_shadowmapping.integer && vid.support.ext_framebuffer_object)
388 if(r_shadow_shadowmapfilterquality < 0)
390 if(strstr(gl_vendor, "NVIDIA"))
392 r_shadow_shadowmapsampler = vid.support.arb_shadow;
393 r_shadow_shadowmappcf = 1;
395 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
396 r_shadow_shadowmappcf = 1;
397 else if(strstr(gl_vendor, "ATI"))
398 r_shadow_shadowmappcf = 1;
400 r_shadow_shadowmapsampler = vid.support.arb_shadow;
404 switch (r_shadow_shadowmapfilterquality)
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 1;
417 r_shadow_shadowmappcf = 2;
421 switch (r_shadow_shadowmaptexturetype)
424 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
427 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
433 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
435 else if(vid.support.arb_texture_rectangle)
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
443 case RENDERPATH_GL13:
445 case RENDERPATH_GL11:
450 void R_Shadow_FreeShadowMaps(void)
454 R_Shadow_SetShadowMode();
456 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
461 if (r_shadow_fborectangle)
462 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
463 r_shadow_fborectangle = 0;
466 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
468 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
469 if (r_shadow_fbocubeside[i])
470 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
471 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
473 if (r_shadow_shadowmaprectangletexture)
474 R_FreeTexture(r_shadow_shadowmaprectangletexture);
475 r_shadow_shadowmaprectangletexture = NULL;
477 if (r_shadow_shadowmap2dtexture)
478 R_FreeTexture(r_shadow_shadowmap2dtexture);
479 r_shadow_shadowmap2dtexture = NULL;
481 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
482 if (r_shadow_shadowmapcubetexture[i])
483 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
484 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
486 if (r_shadow_shadowmapvsdcttexture)
487 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
488 r_shadow_shadowmapvsdcttexture = NULL;
493 void r_shadow_start(void)
495 // allocate vertex processing arrays
497 r_shadow_attenuationgradienttexture = NULL;
498 r_shadow_attenuation2dtexture = NULL;
499 r_shadow_attenuation3dtexture = NULL;
500 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
501 r_shadow_shadowmaprectangletexture = NULL;
502 r_shadow_shadowmap2dtexture = NULL;
503 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
504 r_shadow_shadowmapvsdcttexture = NULL;
505 r_shadow_shadowmapmaxsize = 0;
506 r_shadow_shadowmapsize = 0;
507 r_shadow_shadowmaplod = 0;
508 r_shadow_shadowmapfilterquality = -1;
509 r_shadow_shadowmaptexturetype = -1;
510 r_shadow_shadowmapdepthbits = 0;
511 r_shadow_shadowmapvsdct = false;
512 r_shadow_shadowmapsampler = false;
513 r_shadow_shadowmappcf = 0;
514 r_shadow_fborectangle = 0;
516 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
518 R_Shadow_FreeShadowMaps();
520 r_shadow_texturepool = NULL;
521 r_shadow_filters_texturepool = NULL;
522 R_Shadow_ValidateCvars();
523 R_Shadow_MakeTextures();
524 maxshadowtriangles = 0;
525 shadowelements = NULL;
526 maxshadowvertices = 0;
527 shadowvertex3f = NULL;
535 shadowmarklist = NULL;
540 shadowsideslist = NULL;
541 r_shadow_buffer_numleafpvsbytes = 0;
542 r_shadow_buffer_visitingleafpvs = NULL;
543 r_shadow_buffer_leafpvs = NULL;
544 r_shadow_buffer_leaflist = NULL;
545 r_shadow_buffer_numsurfacepvsbytes = 0;
546 r_shadow_buffer_surfacepvs = NULL;
547 r_shadow_buffer_surfacelist = NULL;
548 r_shadow_buffer_surfacesides = NULL;
549 r_shadow_buffer_numshadowtrispvsbytes = 0;
550 r_shadow_buffer_shadowtrispvs = NULL;
551 r_shadow_buffer_numlighttrispvsbytes = 0;
552 r_shadow_buffer_lighttrispvs = NULL;
555 void r_shadow_shutdown(void)
558 R_Shadow_UncompileWorldLights();
560 R_Shadow_FreeShadowMaps();
564 r_shadow_attenuationgradienttexture = NULL;
565 r_shadow_attenuation2dtexture = NULL;
566 r_shadow_attenuation3dtexture = NULL;
567 R_FreeTexturePool(&r_shadow_texturepool);
568 R_FreeTexturePool(&r_shadow_filters_texturepool);
569 maxshadowtriangles = 0;
571 Mem_Free(shadowelements);
572 shadowelements = NULL;
574 Mem_Free(shadowvertex3f);
575 shadowvertex3f = NULL;
578 Mem_Free(vertexupdate);
581 Mem_Free(vertexremap);
587 Mem_Free(shadowmark);
590 Mem_Free(shadowmarklist);
591 shadowmarklist = NULL;
596 Mem_Free(shadowsides);
599 Mem_Free(shadowsideslist);
600 shadowsideslist = NULL;
601 r_shadow_buffer_numleafpvsbytes = 0;
602 if (r_shadow_buffer_visitingleafpvs)
603 Mem_Free(r_shadow_buffer_visitingleafpvs);
604 r_shadow_buffer_visitingleafpvs = NULL;
605 if (r_shadow_buffer_leafpvs)
606 Mem_Free(r_shadow_buffer_leafpvs);
607 r_shadow_buffer_leafpvs = NULL;
608 if (r_shadow_buffer_leaflist)
609 Mem_Free(r_shadow_buffer_leaflist);
610 r_shadow_buffer_leaflist = NULL;
611 r_shadow_buffer_numsurfacepvsbytes = 0;
612 if (r_shadow_buffer_surfacepvs)
613 Mem_Free(r_shadow_buffer_surfacepvs);
614 r_shadow_buffer_surfacepvs = NULL;
615 if (r_shadow_buffer_surfacelist)
616 Mem_Free(r_shadow_buffer_surfacelist);
617 r_shadow_buffer_surfacelist = NULL;
618 if (r_shadow_buffer_surfacesides)
619 Mem_Free(r_shadow_buffer_surfacesides);
620 r_shadow_buffer_surfacesides = NULL;
621 r_shadow_buffer_numshadowtrispvsbytes = 0;
622 if (r_shadow_buffer_shadowtrispvs)
623 Mem_Free(r_shadow_buffer_shadowtrispvs);
624 r_shadow_buffer_numlighttrispvsbytes = 0;
625 if (r_shadow_buffer_lighttrispvs)
626 Mem_Free(r_shadow_buffer_lighttrispvs);
629 void r_shadow_newmap(void)
631 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
632 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
633 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
634 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
635 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
636 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
637 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
638 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
639 R_Shadow_EditLights_Reload_f();
642 void R_Shadow_Init(void)
644 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
645 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
646 Cvar_RegisterVariable(&r_shadow_usenormalmap);
647 Cvar_RegisterVariable(&r_shadow_debuglight);
648 Cvar_RegisterVariable(&r_shadow_gloss);
649 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
650 Cvar_RegisterVariable(&r_shadow_glossintensity);
651 Cvar_RegisterVariable(&r_shadow_glossexponent);
652 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
653 Cvar_RegisterVariable(&r_shadow_glossexact);
654 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
655 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
656 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
657 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
658 Cvar_RegisterVariable(&r_shadow_portallight);
659 Cvar_RegisterVariable(&r_shadow_projectdistance);
660 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
661 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
662 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
663 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
664 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
665 Cvar_RegisterVariable(&r_shadow_realtime_world);
666 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
667 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
668 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
669 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
670 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
671 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
672 Cvar_RegisterVariable(&r_shadow_scissor);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
678 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
679 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
680 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
681 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
682 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
683 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
684 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
685 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
686 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
687 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
688 Cvar_RegisterVariable(&r_shadow_culltriangles);
689 Cvar_RegisterVariable(&r_shadow_polygonfactor);
690 Cvar_RegisterVariable(&r_shadow_polygonoffset);
691 Cvar_RegisterVariable(&r_shadow_texture3d);
692 Cvar_RegisterVariable(&r_coronas);
693 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
694 Cvar_RegisterVariable(&r_coronas_occlusionquery);
695 Cvar_RegisterVariable(&gl_flashblend);
696 Cvar_RegisterVariable(&gl_ext_separatestencil);
697 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
698 if (gamemode == GAME_TENEBRAE)
700 Cvar_SetValue("r_shadow_gloss", 2);
701 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
703 R_Shadow_EditLights_Init();
704 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
705 maxshadowtriangles = 0;
706 shadowelements = NULL;
707 maxshadowvertices = 0;
708 shadowvertex3f = NULL;
716 shadowmarklist = NULL;
721 shadowsideslist = NULL;
722 r_shadow_buffer_numleafpvsbytes = 0;
723 r_shadow_buffer_visitingleafpvs = NULL;
724 r_shadow_buffer_leafpvs = NULL;
725 r_shadow_buffer_leaflist = NULL;
726 r_shadow_buffer_numsurfacepvsbytes = 0;
727 r_shadow_buffer_surfacepvs = NULL;
728 r_shadow_buffer_surfacelist = NULL;
729 r_shadow_buffer_surfacesides = NULL;
730 r_shadow_buffer_shadowtrispvs = NULL;
731 r_shadow_buffer_lighttrispvs = NULL;
732 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
735 matrix4x4_t matrix_attenuationxyz =
738 {0.5, 0.0, 0.0, 0.5},
739 {0.0, 0.5, 0.0, 0.5},
740 {0.0, 0.0, 0.5, 0.5},
745 matrix4x4_t matrix_attenuationz =
748 {0.0, 0.0, 0.5, 0.5},
749 {0.0, 0.0, 0.0, 0.5},
750 {0.0, 0.0, 0.0, 0.5},
755 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
757 numvertices = ((numvertices + 255) & ~255) * vertscale;
758 numtriangles = ((numtriangles + 255) & ~255) * triscale;
759 // make sure shadowelements is big enough for this volume
760 if (maxshadowtriangles < numtriangles)
762 maxshadowtriangles = numtriangles;
764 Mem_Free(shadowelements);
765 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
767 // make sure shadowvertex3f is big enough for this volume
768 if (maxshadowvertices < numvertices)
770 maxshadowvertices = numvertices;
772 Mem_Free(shadowvertex3f);
773 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
777 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
779 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
780 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
781 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
782 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
783 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
785 if (r_shadow_buffer_visitingleafpvs)
786 Mem_Free(r_shadow_buffer_visitingleafpvs);
787 if (r_shadow_buffer_leafpvs)
788 Mem_Free(r_shadow_buffer_leafpvs);
789 if (r_shadow_buffer_leaflist)
790 Mem_Free(r_shadow_buffer_leaflist);
791 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
792 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
793 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
794 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
796 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
798 if (r_shadow_buffer_surfacepvs)
799 Mem_Free(r_shadow_buffer_surfacepvs);
800 if (r_shadow_buffer_surfacelist)
801 Mem_Free(r_shadow_buffer_surfacelist);
802 if (r_shadow_buffer_surfacesides)
803 Mem_Free(r_shadow_buffer_surfacesides);
804 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
805 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
806 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
807 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
809 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
811 if (r_shadow_buffer_shadowtrispvs)
812 Mem_Free(r_shadow_buffer_shadowtrispvs);
813 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
814 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
816 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
818 if (r_shadow_buffer_lighttrispvs)
819 Mem_Free(r_shadow_buffer_lighttrispvs);
820 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
821 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
825 void R_Shadow_PrepareShadowMark(int numtris)
827 // make sure shadowmark is big enough for this volume
828 if (maxshadowmark < numtris)
830 maxshadowmark = numtris;
832 Mem_Free(shadowmark);
834 Mem_Free(shadowmarklist);
835 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
836 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
840 // if shadowmarkcount wrapped we clear the array and adjust accordingly
841 if (shadowmarkcount == 0)
844 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
849 void R_Shadow_PrepareShadowSides(int numtris)
851 if (maxshadowsides < numtris)
853 maxshadowsides = numtris;
855 Mem_Free(shadowsides);
857 Mem_Free(shadowsideslist);
858 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
859 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
864 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)
867 int outtriangles = 0, outvertices = 0;
870 float ratio, direction[3], projectvector[3];
872 if (projectdirection)
873 VectorScale(projectdirection, projectdistance, projectvector);
875 VectorClear(projectvector);
877 // create the vertices
878 if (projectdirection)
880 for (i = 0;i < numshadowmarktris;i++)
882 element = inelement3i + shadowmarktris[i] * 3;
883 for (j = 0;j < 3;j++)
885 if (vertexupdate[element[j]] != vertexupdatenum)
887 vertexupdate[element[j]] = vertexupdatenum;
888 vertexremap[element[j]] = outvertices;
889 vertex = invertex3f + element[j] * 3;
890 // project one copy of the vertex according to projectvector
891 VectorCopy(vertex, outvertex3f);
892 VectorAdd(vertex, projectvector, (outvertex3f + 3));
901 for (i = 0;i < numshadowmarktris;i++)
903 element = inelement3i + shadowmarktris[i] * 3;
904 for (j = 0;j < 3;j++)
906 if (vertexupdate[element[j]] != vertexupdatenum)
908 vertexupdate[element[j]] = vertexupdatenum;
909 vertexremap[element[j]] = outvertices;
910 vertex = invertex3f + element[j] * 3;
911 // project one copy of the vertex to the sphere radius of the light
912 // (FIXME: would projecting it to the light box be better?)
913 VectorSubtract(vertex, projectorigin, direction);
914 ratio = projectdistance / VectorLength(direction);
915 VectorCopy(vertex, outvertex3f);
916 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
924 if (r_shadow_frontsidecasting.integer)
926 for (i = 0;i < numshadowmarktris;i++)
928 int remappedelement[3];
930 const int *neighbortriangle;
932 markindex = shadowmarktris[i] * 3;
933 element = inelement3i + markindex;
934 neighbortriangle = inneighbor3i + markindex;
935 // output the front and back triangles
936 outelement3i[0] = vertexremap[element[0]];
937 outelement3i[1] = vertexremap[element[1]];
938 outelement3i[2] = vertexremap[element[2]];
939 outelement3i[3] = vertexremap[element[2]] + 1;
940 outelement3i[4] = vertexremap[element[1]] + 1;
941 outelement3i[5] = vertexremap[element[0]] + 1;
945 // output the sides (facing outward from this triangle)
946 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
948 remappedelement[0] = vertexremap[element[0]];
949 remappedelement[1] = vertexremap[element[1]];
950 outelement3i[0] = remappedelement[1];
951 outelement3i[1] = remappedelement[0];
952 outelement3i[2] = remappedelement[0] + 1;
953 outelement3i[3] = remappedelement[1];
954 outelement3i[4] = remappedelement[0] + 1;
955 outelement3i[5] = remappedelement[1] + 1;
960 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
962 remappedelement[1] = vertexremap[element[1]];
963 remappedelement[2] = vertexremap[element[2]];
964 outelement3i[0] = remappedelement[2];
965 outelement3i[1] = remappedelement[1];
966 outelement3i[2] = remappedelement[1] + 1;
967 outelement3i[3] = remappedelement[2];
968 outelement3i[4] = remappedelement[1] + 1;
969 outelement3i[5] = remappedelement[2] + 1;
974 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
976 remappedelement[0] = vertexremap[element[0]];
977 remappedelement[2] = vertexremap[element[2]];
978 outelement3i[0] = remappedelement[0];
979 outelement3i[1] = remappedelement[2];
980 outelement3i[2] = remappedelement[2] + 1;
981 outelement3i[3] = remappedelement[0];
982 outelement3i[4] = remappedelement[2] + 1;
983 outelement3i[5] = remappedelement[0] + 1;
992 for (i = 0;i < numshadowmarktris;i++)
994 int remappedelement[3];
996 const int *neighbortriangle;
998 markindex = shadowmarktris[i] * 3;
999 element = inelement3i + markindex;
1000 neighbortriangle = inneighbor3i + markindex;
1001 // output the front and back triangles
1002 outelement3i[0] = vertexremap[element[2]];
1003 outelement3i[1] = vertexremap[element[1]];
1004 outelement3i[2] = vertexremap[element[0]];
1005 outelement3i[3] = vertexremap[element[0]] + 1;
1006 outelement3i[4] = vertexremap[element[1]] + 1;
1007 outelement3i[5] = vertexremap[element[2]] + 1;
1011 // output the sides (facing outward from this triangle)
1012 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1014 remappedelement[0] = vertexremap[element[0]];
1015 remappedelement[1] = vertexremap[element[1]];
1016 outelement3i[0] = remappedelement[0];
1017 outelement3i[1] = remappedelement[1];
1018 outelement3i[2] = remappedelement[1] + 1;
1019 outelement3i[3] = remappedelement[0];
1020 outelement3i[4] = remappedelement[1] + 1;
1021 outelement3i[5] = remappedelement[0] + 1;
1026 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1028 remappedelement[1] = vertexremap[element[1]];
1029 remappedelement[2] = vertexremap[element[2]];
1030 outelement3i[0] = remappedelement[1];
1031 outelement3i[1] = remappedelement[2];
1032 outelement3i[2] = remappedelement[2] + 1;
1033 outelement3i[3] = remappedelement[1];
1034 outelement3i[4] = remappedelement[2] + 1;
1035 outelement3i[5] = remappedelement[1] + 1;
1040 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1042 remappedelement[0] = vertexremap[element[0]];
1043 remappedelement[2] = vertexremap[element[2]];
1044 outelement3i[0] = remappedelement[2];
1045 outelement3i[1] = remappedelement[0];
1046 outelement3i[2] = remappedelement[0] + 1;
1047 outelement3i[3] = remappedelement[2];
1048 outelement3i[4] = remappedelement[0] + 1;
1049 outelement3i[5] = remappedelement[2] + 1;
1057 *outnumvertices = outvertices;
1058 return outtriangles;
1061 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)
1064 int outtriangles = 0, outvertices = 0;
1066 const float *vertex;
1067 float ratio, direction[3], projectvector[3];
1070 if (projectdirection)
1071 VectorScale(projectdirection, projectdistance, projectvector);
1073 VectorClear(projectvector);
1075 for (i = 0;i < numshadowmarktris;i++)
1077 int remappedelement[3];
1079 const int *neighbortriangle;
1081 markindex = shadowmarktris[i] * 3;
1082 neighbortriangle = inneighbor3i + markindex;
1083 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1084 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1085 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1086 if (side[0] + side[1] + side[2] == 0)
1090 element = inelement3i + markindex;
1092 // create the vertices
1093 for (j = 0;j < 3;j++)
1095 if (side[j] + side[j+1] == 0)
1098 if (vertexupdate[k] != vertexupdatenum)
1100 vertexupdate[k] = vertexupdatenum;
1101 vertexremap[k] = outvertices;
1102 vertex = invertex3f + k * 3;
1103 VectorCopy(vertex, outvertex3f);
1104 if (projectdirection)
1106 // project one copy of the vertex according to projectvector
1107 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1111 // project one copy of the vertex to the sphere radius of the light
1112 // (FIXME: would projecting it to the light box be better?)
1113 VectorSubtract(vertex, projectorigin, direction);
1114 ratio = projectdistance / VectorLength(direction);
1115 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1122 // output the sides (facing outward from this triangle)
1125 remappedelement[0] = vertexremap[element[0]];
1126 remappedelement[1] = vertexremap[element[1]];
1127 outelement3i[0] = remappedelement[1];
1128 outelement3i[1] = remappedelement[0];
1129 outelement3i[2] = remappedelement[0] + 1;
1130 outelement3i[3] = remappedelement[1];
1131 outelement3i[4] = remappedelement[0] + 1;
1132 outelement3i[5] = remappedelement[1] + 1;
1139 remappedelement[1] = vertexremap[element[1]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[2];
1142 outelement3i[1] = remappedelement[1];
1143 outelement3i[2] = remappedelement[1] + 1;
1144 outelement3i[3] = remappedelement[2];
1145 outelement3i[4] = remappedelement[1] + 1;
1146 outelement3i[5] = remappedelement[2] + 1;
1153 remappedelement[0] = vertexremap[element[0]];
1154 remappedelement[2] = vertexremap[element[2]];
1155 outelement3i[0] = remappedelement[0];
1156 outelement3i[1] = remappedelement[2];
1157 outelement3i[2] = remappedelement[2] + 1;
1158 outelement3i[3] = remappedelement[0];
1159 outelement3i[4] = remappedelement[2] + 1;
1160 outelement3i[5] = remappedelement[0] + 1;
1167 *outnumvertices = outvertices;
1168 return outtriangles;
1171 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)
1177 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1179 tend = firsttriangle + numtris;
1180 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1182 // surface box entirely inside light box, no box cull
1183 if (projectdirection)
1185 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1187 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1188 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1189 shadowmarklist[numshadowmark++] = t;
1194 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1195 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1196 shadowmarklist[numshadowmark++] = t;
1201 // surface box not entirely inside light box, cull each triangle
1202 if (projectdirection)
1204 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1206 v[0] = invertex3f + e[0] * 3;
1207 v[1] = invertex3f + e[1] * 3;
1208 v[2] = invertex3f + e[2] * 3;
1209 TriangleNormal(v[0], v[1], v[2], normal);
1210 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1211 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1212 shadowmarklist[numshadowmark++] = t;
1217 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1219 v[0] = invertex3f + e[0] * 3;
1220 v[1] = invertex3f + e[1] * 3;
1221 v[2] = invertex3f + e[2] * 3;
1222 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1223 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1224 shadowmarklist[numshadowmark++] = t;
1230 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1235 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1237 // check if the shadow volume intersects the near plane
1239 // a ray between the eye and light origin may intersect the caster,
1240 // indicating that the shadow may touch the eye location, however we must
1241 // test the near plane (a polygon), not merely the eye location, so it is
1242 // easiest to enlarge the caster bounding shape slightly for this.
1248 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)
1250 int i, tris, outverts;
1251 if (projectdistance < 0.1)
1253 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1256 if (!numverts || !nummarktris)
1258 // make sure shadowelements is big enough for this volume
1259 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1260 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1262 if (maxvertexupdate < numverts)
1264 maxvertexupdate = numverts;
1266 Mem_Free(vertexupdate);
1268 Mem_Free(vertexremap);
1269 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1270 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1271 vertexupdatenum = 0;
1274 if (vertexupdatenum == 0)
1276 vertexupdatenum = 1;
1277 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1278 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1281 for (i = 0;i < nummarktris;i++)
1282 shadowmark[marktris[i]] = shadowmarkcount;
1284 if (r_shadow_compilingrtlight)
1286 // if we're compiling an rtlight, capture the mesh
1287 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1288 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1289 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1290 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1294 // decide which type of shadow to generate and set stencil mode
1295 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1296 // generate the sides or a solid volume, depending on type
1297 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1298 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1300 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1301 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1302 r_refdef.stats.lights_shadowtriangles += tris;
1304 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1305 GL_LockArrays(0, outverts);
1306 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1308 // increment stencil if frontface is infront of depthbuffer
1309 GL_CullFace(r_refdef.view.cullface_front);
1310 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1311 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1312 // decrement stencil if backface is infront of depthbuffer
1313 GL_CullFace(r_refdef.view.cullface_back);
1314 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1316 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1318 // decrement stencil if backface is behind depthbuffer
1319 GL_CullFace(r_refdef.view.cullface_front);
1320 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1321 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1322 // increment stencil if frontface is behind depthbuffer
1323 GL_CullFace(r_refdef.view.cullface_back);
1324 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1326 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1327 GL_LockArrays(0, 0);
1332 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1334 // p1, p2, p3 are in the cubemap's local coordinate system
1335 // bias = border/(size - border)
1338 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1339 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1340 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1341 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1343 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1344 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1345 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1346 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1348 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1349 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1350 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1352 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1353 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1354 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1355 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1357 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1358 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1359 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1360 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1362 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1363 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1364 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1366 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1367 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1368 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1369 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1371 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1372 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1373 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1374 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1376 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1377 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1378 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1383 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1385 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1386 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1389 VectorSubtract(maxs, mins, radius);
1390 VectorScale(radius, 0.5f, radius);
1391 VectorAdd(mins, radius, center);
1392 Matrix4x4_Transform(worldtolight, center, lightcenter);
1393 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1394 VectorSubtract(lightcenter, lightradius, pmin);
1395 VectorAdd(lightcenter, lightradius, pmax);
1397 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1398 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1399 if(ap1 > bias*an1 && ap2 > bias*an2)
1401 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1402 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1403 if(an1 > bias*ap1 && an2 > bias*ap2)
1405 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1406 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1408 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1409 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1410 if(ap1 > bias*an1 && ap2 > bias*an2)
1412 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1413 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1414 if(an1 > bias*ap1 && an2 > bias*ap2)
1416 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1417 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1419 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1420 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1421 if(ap1 > bias*an1 && ap2 > bias*an2)
1423 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1424 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1425 if(an1 > bias*ap1 && an2 > bias*ap2)
1427 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1428 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1433 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1435 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1437 // p is in the cubemap's local coordinate system
1438 // bias = border/(size - border)
1439 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1440 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1441 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1443 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1444 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1445 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1446 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1447 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1448 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1452 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1456 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1457 float scale = (size - 2*border)/size, len;
1458 float bias = border / (float)(size - border), dp, dn, ap, an;
1459 // check if cone enclosing side would cross frustum plane
1460 scale = 2 / (scale*scale + 2);
1461 for (i = 0;i < 5;i++)
1463 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1465 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1466 len = scale*VectorLength2(n);
1467 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1468 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1469 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1471 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1473 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1474 len = scale*VectorLength(n);
1475 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1476 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1477 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1479 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1480 // check if frustum corners/origin cross plane sides
1481 for (i = 0;i < 5;i++)
1483 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1484 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1485 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1486 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1487 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1488 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1489 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1490 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1491 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1492 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1494 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1497 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)
1505 int mask, surfacemask = 0;
1506 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1508 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1509 tend = firsttriangle + numtris;
1510 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1512 // surface box entirely inside light box, no box cull
1513 if (projectdirection)
1515 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1517 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1518 TriangleNormal(v[0], v[1], v[2], normal);
1519 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1521 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1522 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1523 surfacemask |= mask;
1526 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;
1527 shadowsides[numshadowsides] = mask;
1528 shadowsideslist[numshadowsides++] = t;
1535 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1537 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1538 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1540 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1541 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1542 surfacemask |= mask;
1545 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;
1546 shadowsides[numshadowsides] = mask;
1547 shadowsideslist[numshadowsides++] = t;
1555 // surface box not entirely inside light box, cull each triangle
1556 if (projectdirection)
1558 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1560 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1561 TriangleNormal(v[0], v[1], v[2], normal);
1562 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1563 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1565 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1566 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1567 surfacemask |= mask;
1570 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;
1571 shadowsides[numshadowsides] = mask;
1572 shadowsideslist[numshadowsides++] = t;
1579 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1581 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1582 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1583 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1585 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1586 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1587 surfacemask |= mask;
1590 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1591 shadowsides[numshadowsides] = mask;
1592 shadowsideslist[numshadowsides++] = t;
1601 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)
1603 int i, j, outtriangles = 0;
1604 int *outelement3i[6];
1605 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1607 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1608 // make sure shadowelements is big enough for this mesh
1609 if (maxshadowtriangles < outtriangles)
1610 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1612 // compute the offset and size of the separate index lists for each cubemap side
1614 for (i = 0;i < 6;i++)
1616 outelement3i[i] = shadowelements + outtriangles * 3;
1617 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1618 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1619 outtriangles += sidetotals[i];
1622 // gather up the (sparse) triangles into separate index lists for each cubemap side
1623 for (i = 0;i < numsidetris;i++)
1625 const int *element = elements + sidetris[i] * 3;
1626 for (j = 0;j < 6;j++)
1628 if (sides[i] & (1 << j))
1630 outelement3i[j][0] = element[0];
1631 outelement3i[j][1] = element[1];
1632 outelement3i[j][2] = element[2];
1633 outelement3i[j] += 3;
1638 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1641 static void R_Shadow_MakeTextures_MakeCorona(void)
1645 unsigned char pixels[32][32][4];
1646 for (y = 0;y < 32;y++)
1648 dy = (y - 15.5f) * (1.0f / 16.0f);
1649 for (x = 0;x < 32;x++)
1651 dx = (x - 15.5f) * (1.0f / 16.0f);
1652 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1653 a = bound(0, a, 255);
1654 pixels[y][x][0] = a;
1655 pixels[y][x][1] = a;
1656 pixels[y][x][2] = a;
1657 pixels[y][x][3] = 255;
1660 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1663 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1665 float dist = sqrt(x*x+y*y+z*z);
1666 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1667 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1668 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1671 static void R_Shadow_MakeTextures(void)
1674 float intensity, dist;
1676 R_Shadow_FreeShadowMaps();
1677 R_FreeTexturePool(&r_shadow_texturepool);
1678 r_shadow_texturepool = R_AllocTexturePool();
1679 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1680 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1681 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1682 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1683 for (x = 0;x <= ATTENTABLESIZE;x++)
1685 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1686 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1687 r_shadow_attentable[x] = bound(0, intensity, 1);
1689 // 1D gradient texture
1690 for (x = 0;x < ATTEN1DSIZE;x++)
1691 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1692 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);
1693 // 2D circle texture
1694 for (y = 0;y < ATTEN2DSIZE;y++)
1695 for (x = 0;x < ATTEN2DSIZE;x++)
1696 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);
1697 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);
1698 // 3D sphere texture
1699 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1701 for (z = 0;z < ATTEN3DSIZE;z++)
1702 for (y = 0;y < ATTEN3DSIZE;y++)
1703 for (x = 0;x < ATTEN3DSIZE;x++)
1704 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));
1705 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);
1708 r_shadow_attenuation3dtexture = NULL;
1711 R_Shadow_MakeTextures_MakeCorona();
1713 // Editor light sprites
1714 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1731 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1732 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1749 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1750 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1767 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1768 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1785 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1786 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1803 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1804 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1821 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1824 void R_Shadow_ValidateCvars(void)
1826 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1827 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1828 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1829 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1830 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1831 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1834 void R_Shadow_RenderMode_Begin(void)
1840 R_Shadow_ValidateCvars();
1842 if (!r_shadow_attenuation2dtexture
1843 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1844 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1845 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1846 R_Shadow_MakeTextures();
1849 R_Mesh_ColorPointer(NULL, 0, 0);
1850 R_Mesh_ResetTextureState();
1851 GL_BlendFunc(GL_ONE, GL_ZERO);
1852 GL_DepthRange(0, 1);
1853 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1855 GL_DepthMask(false);
1856 GL_Color(0, 0, 0, 1);
1857 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1859 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1861 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1863 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1864 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1866 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1868 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1869 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1873 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1874 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1877 switch(vid.renderpath)
1879 case RENDERPATH_GL20:
1880 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1882 case RENDERPATH_GL13:
1883 case RENDERPATH_GL11:
1884 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1885 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1886 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1887 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1888 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1889 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1891 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1897 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1898 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1899 r_shadow_drawbuffer = drawbuffer;
1900 r_shadow_readbuffer = readbuffer;
1902 r_shadow_cullface_front = r_refdef.view.cullface_front;
1903 r_shadow_cullface_back = r_refdef.view.cullface_back;
1906 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1908 rsurface.rtlight = rtlight;
1911 void R_Shadow_RenderMode_Reset(void)
1914 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1916 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1918 if (vid.support.ext_framebuffer_object)
1920 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1923 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1924 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1926 R_SetViewport(&r_refdef.view.viewport);
1927 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1928 R_Mesh_ColorPointer(NULL, 0, 0);
1929 R_Mesh_ResetTextureState();
1930 GL_DepthRange(0, 1);
1932 GL_DepthMask(false);
1933 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1934 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1935 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1936 qglStencilMask(~0);CHECKGLERROR
1937 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1938 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1939 r_refdef.view.cullface_front = r_shadow_cullface_front;
1940 r_refdef.view.cullface_back = r_shadow_cullface_back;
1941 GL_CullFace(r_refdef.view.cullface_back);
1942 GL_Color(1, 1, 1, 1);
1943 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1944 GL_BlendFunc(GL_ONE, GL_ZERO);
1945 R_SetupGenericShader(false);
1946 r_shadow_usingshadowmaprect = false;
1947 r_shadow_usingshadowmapcube = false;
1948 r_shadow_usingshadowmap2d = false;
1952 void R_Shadow_ClearStencil(void)
1955 GL_Clear(GL_STENCIL_BUFFER_BIT);
1956 r_refdef.stats.lights_clears++;
1959 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1961 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1962 if (r_shadow_rendermode == mode)
1965 R_Shadow_RenderMode_Reset();
1966 GL_ColorMask(0, 0, 0, 0);
1967 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1968 R_SetupDepthOrShadowShader();
1969 qglDepthFunc(GL_LESS);CHECKGLERROR
1970 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1971 r_shadow_rendermode = mode;
1976 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1977 GL_CullFace(GL_NONE);
1978 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1979 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1981 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1982 GL_CullFace(GL_NONE);
1983 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1984 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1986 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1987 GL_CullFace(GL_NONE);
1988 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1989 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1990 qglStencilMask(~0);CHECKGLERROR
1991 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1992 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1993 qglStencilMask(~0);CHECKGLERROR
1994 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1996 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1997 GL_CullFace(GL_NONE);
1998 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1999 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2000 qglStencilMask(~0);CHECKGLERROR
2001 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2002 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2003 qglStencilMask(~0);CHECKGLERROR
2004 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2009 static void R_Shadow_MakeVSDCT(void)
2011 // maps to a 2x3 texture rectangle with normalized coordinates
2016 // stores abs(dir.xy), offset.xy/2.5
2017 unsigned char data[4*6] =
2019 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2020 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2021 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2022 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2023 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2024 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2026 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2029 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2033 float nearclip, farclip, bias;
2034 r_viewport_t viewport;
2037 maxsize = r_shadow_shadowmapmaxsize;
2038 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2040 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2041 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2042 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2043 r_shadow_shadowmapside = side;
2044 r_shadow_shadowmapsize = size;
2045 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2047 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2048 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2049 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2050 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2052 // complex unrolled cube approach (more flexible)
2053 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2054 R_Shadow_MakeVSDCT();
2055 if (!r_shadow_shadowmap2dtexture)
2058 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2059 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2060 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2061 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2062 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2063 // render depth into the fbo, do not render color at all
2064 qglDrawBuffer(GL_NONE);CHECKGLERROR
2065 qglReadBuffer(GL_NONE);CHECKGLERROR
2066 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2067 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2069 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2070 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2075 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2076 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2077 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2078 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2080 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2082 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2083 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2084 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2085 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2087 // complex unrolled cube approach (more flexible)
2088 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2089 R_Shadow_MakeVSDCT();
2090 if (!r_shadow_shadowmaprectangletexture)
2093 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2094 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2095 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2096 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2097 // render depth into the fbo, do not render color at all
2098 qglDrawBuffer(GL_NONE);CHECKGLERROR
2099 qglReadBuffer(GL_NONE);CHECKGLERROR
2100 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2101 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2103 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2104 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2109 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2110 r_shadow_shadowmap_texturescale[0] = 1.0f;
2111 r_shadow_shadowmap_texturescale[1] = 1.0f;
2112 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2114 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2116 r_shadow_shadowmap_parameters[0] = 1.0f;
2117 r_shadow_shadowmap_parameters[1] = 1.0f;
2118 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2119 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2121 // simple cube approach
2122 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2125 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2126 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2127 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2128 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
2129 // render depth into the fbo, do not render color at all
2130 qglDrawBuffer(GL_NONE);CHECKGLERROR
2131 qglReadBuffer(GL_NONE);CHECKGLERROR
2132 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2133 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2135 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2136 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2141 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2142 r_shadow_shadowmap_texturescale[0] = 0.0f;
2143 r_shadow_shadowmap_texturescale[1] = 0.0f;
2144 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2147 R_Shadow_RenderMode_Reset();
2150 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2151 R_SetupDepthOrShadowShader();
2155 R_SetupShowDepthShader();
2156 qglClearColor(1,1,1,1);CHECKGLERROR
2159 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2166 R_SetViewport(&viewport);
2167 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2168 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2170 int flipped = (side&1)^(side>>2);
2171 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2172 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2173 GL_CullFace(r_refdef.view.cullface_back);
2175 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2177 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
2180 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2184 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2188 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2189 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2190 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2191 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2194 R_Shadow_RenderMode_Reset();
2195 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2198 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2202 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2203 // only draw light where this geometry was already rendered AND the
2204 // stencil is 128 (values other than this mean shadow)
2205 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2207 r_shadow_rendermode = r_shadow_lightingrendermode;
2208 // do global setup needed for the chosen lighting mode
2209 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2211 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2212 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2216 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2218 r_shadow_usingshadowmap2d = true;
2219 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2222 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2224 r_shadow_usingshadowmaprect = true;
2225 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2228 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2230 r_shadow_usingshadowmapcube = true;
2231 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2235 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2237 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2242 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2243 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2247 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2250 R_Shadow_RenderMode_Reset();
2251 GL_BlendFunc(GL_ONE, GL_ONE);
2252 GL_DepthRange(0, 1);
2253 GL_DepthTest(r_showshadowvolumes.integer < 2);
2254 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2255 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2256 GL_CullFace(GL_NONE);
2257 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2260 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2263 R_Shadow_RenderMode_Reset();
2264 GL_BlendFunc(GL_ONE, GL_ONE);
2265 GL_DepthRange(0, 1);
2266 GL_DepthTest(r_showlighting.integer < 2);
2267 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2270 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2274 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2275 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2277 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2280 void R_Shadow_RenderMode_End(void)
2283 R_Shadow_RenderMode_Reset();
2284 R_Shadow_RenderMode_ActiveLight(NULL);
2286 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2287 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2290 int bboxedges[12][2] =
2309 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2311 int i, ix1, iy1, ix2, iy2;
2312 float x1, y1, x2, y2;
2314 float vertex[20][3];
2323 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2324 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2325 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2326 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2328 if (!r_shadow_scissor.integer)
2331 // if view is inside the light box, just say yes it's visible
2332 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2335 x1 = y1 = x2 = y2 = 0;
2337 // transform all corners that are infront of the nearclip plane
2338 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2339 plane4f[3] = r_refdef.view.frustum[4].dist;
2341 for (i = 0;i < 8;i++)
2343 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2344 dist[i] = DotProduct4(corner[i], plane4f);
2345 sign[i] = dist[i] > 0;
2348 VectorCopy(corner[i], vertex[numvertices]);
2352 // if some points are behind the nearclip, add clipped edge points to make
2353 // sure that the scissor boundary is complete
2354 if (numvertices > 0 && numvertices < 8)
2356 // add clipped edge points
2357 for (i = 0;i < 12;i++)
2359 j = bboxedges[i][0];
2360 k = bboxedges[i][1];
2361 if (sign[j] != sign[k])
2363 f = dist[j] / (dist[j] - dist[k]);
2364 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2370 // if we have no points to check, the light is behind the view plane
2374 // if we have some points to transform, check what screen area is covered
2375 x1 = y1 = x2 = y2 = 0;
2377 //Con_Printf("%i vertices to transform...\n", numvertices);
2378 for (i = 0;i < numvertices;i++)
2380 VectorCopy(vertex[i], v);
2381 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2382 //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]);
2385 if (x1 > v2[0]) x1 = v2[0];
2386 if (x2 < v2[0]) x2 = v2[0];
2387 if (y1 > v2[1]) y1 = v2[1];
2388 if (y2 < v2[1]) y2 = v2[1];
2397 // now convert the scissor rectangle to integer screen coordinates
2398 ix1 = (int)(x1 - 1.0f);
2399 iy1 = vid.height - (int)(y2 - 1.0f);
2400 ix2 = (int)(x2 + 1.0f);
2401 iy2 = vid.height - (int)(y1 + 1.0f);
2402 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2404 // clamp it to the screen
2405 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2406 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2407 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2408 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2410 // if it is inside out, it's not visible
2411 if (ix2 <= ix1 || iy2 <= iy1)
2414 // the light area is visible, set up the scissor rectangle
2415 r_shadow_lightscissor[0] = ix1;
2416 r_shadow_lightscissor[1] = iy1;
2417 r_shadow_lightscissor[2] = ix2 - ix1;
2418 r_shadow_lightscissor[3] = iy2 - iy1;
2420 r_refdef.stats.lights_scissored++;
2424 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2426 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2427 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2428 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2429 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2430 switch (r_shadow_rendermode)
2432 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2433 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2434 if (VectorLength2(diffusecolor) > 0)
2436 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2438 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2439 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2440 if ((dot = DotProduct(n, v)) < 0)
2442 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2443 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2446 VectorCopy(ambientcolor, color4f);
2447 if (r_refdef.fogenabled)
2450 f = RSurf_FogVertex(vertex3f);
2451 VectorScale(color4f, f, color4f);
2458 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2460 VectorCopy(ambientcolor, color4f);
2461 if (r_refdef.fogenabled)
2464 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2465 f = RSurf_FogVertex(vertex3f);
2466 VectorScale(color4f, f, color4f);
2472 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2473 if (VectorLength2(diffusecolor) > 0)
2475 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2477 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2478 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2480 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2481 if ((dot = DotProduct(n, v)) < 0)
2483 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2484 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2485 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2486 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2490 color4f[0] = ambientcolor[0] * distintensity;
2491 color4f[1] = ambientcolor[1] * distintensity;
2492 color4f[2] = ambientcolor[2] * distintensity;
2494 if (r_refdef.fogenabled)
2497 f = RSurf_FogVertex(vertex3f);
2498 VectorScale(color4f, f, color4f);
2502 VectorClear(color4f);
2508 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2510 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2511 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2513 color4f[0] = ambientcolor[0] * distintensity;
2514 color4f[1] = ambientcolor[1] * distintensity;
2515 color4f[2] = ambientcolor[2] * distintensity;
2516 if (r_refdef.fogenabled)
2519 f = RSurf_FogVertex(vertex3f);
2520 VectorScale(color4f, f, color4f);
2524 VectorClear(color4f);
2529 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2530 if (VectorLength2(diffusecolor) > 0)
2532 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2534 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2535 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2537 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2538 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2539 if ((dot = DotProduct(n, v)) < 0)
2541 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2542 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2543 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2544 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2548 color4f[0] = ambientcolor[0] * distintensity;
2549 color4f[1] = ambientcolor[1] * distintensity;
2550 color4f[2] = ambientcolor[2] * distintensity;
2552 if (r_refdef.fogenabled)
2555 f = RSurf_FogVertex(vertex3f);
2556 VectorScale(color4f, f, color4f);
2560 VectorClear(color4f);
2566 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2568 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2569 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2571 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2572 color4f[0] = ambientcolor[0] * distintensity;
2573 color4f[1] = ambientcolor[1] * distintensity;
2574 color4f[2] = ambientcolor[2] * distintensity;
2575 if (r_refdef.fogenabled)
2578 f = RSurf_FogVertex(vertex3f);
2579 VectorScale(color4f, f, color4f);
2583 VectorClear(color4f);
2593 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)
2595 // used to display how many times a surface is lit for level design purposes
2596 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2599 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)
2601 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2602 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2603 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2604 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2606 R_Mesh_ColorPointer(NULL, 0, 0);
2607 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2608 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2609 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2610 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2611 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2612 if (rsurface.texture->backgroundcurrentskinframe)
2614 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2615 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2616 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2617 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2619 //R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
2620 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2621 if(rsurface.texture->colormapping)
2623 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2624 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2626 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2627 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2628 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2629 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2630 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2631 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2633 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2635 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2636 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2638 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2642 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2649 int newnumtriangles;
2653 int maxtriangles = 4096;
2654 int newelements[4096*3];
2655 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2656 for (renders = 0;renders < 64;renders++)
2661 newnumtriangles = 0;
2663 // due to low fillrate on the cards this vertex lighting path is
2664 // designed for, we manually cull all triangles that do not
2665 // contain a lit vertex
2666 // this builds batches of triangles from multiple surfaces and
2667 // renders them at once
2668 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2670 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2672 if (newnumtriangles)
2674 newfirstvertex = min(newfirstvertex, e[0]);
2675 newlastvertex = max(newlastvertex, e[0]);
2679 newfirstvertex = e[0];
2680 newlastvertex = e[0];
2682 newfirstvertex = min(newfirstvertex, e[1]);
2683 newlastvertex = max(newlastvertex, e[1]);
2684 newfirstvertex = min(newfirstvertex, e[2]);
2685 newlastvertex = max(newlastvertex, e[2]);
2691 if (newnumtriangles >= maxtriangles)
2693 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2694 newnumtriangles = 0;
2700 if (newnumtriangles >= 1)
2702 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2705 // if we couldn't find any lit triangles, exit early
2708 // now reduce the intensity for the next overbright pass
2709 // we have to clamp to 0 here incase the drivers have improper
2710 // handling of negative colors
2711 // (some old drivers even have improper handling of >1 color)
2713 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2715 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2717 c[0] = max(0, c[0] - 1);
2718 c[1] = max(0, c[1] - 1);
2719 c[2] = max(0, c[2] - 1);
2731 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)
2733 // OpenGL 1.1 path (anything)
2734 float ambientcolorbase[3], diffusecolorbase[3];
2735 float ambientcolorpants[3], diffusecolorpants[3];
2736 float ambientcolorshirt[3], diffusecolorshirt[3];
2738 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2739 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2740 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2741 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2742 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2743 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2744 switch(r_shadow_rendermode)
2746 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2747 memset(&m, 0, sizeof(m));
2748 m.tex[0] = R_GetTexture(basetexture);
2749 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2750 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2751 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2752 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2753 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2754 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2755 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2756 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2757 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2758 R_Mesh_TextureState(&m);
2760 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2761 memset(&m, 0, sizeof(m));
2762 m.tex[0] = R_GetTexture(basetexture);
2763 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2764 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2765 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2766 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2767 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2768 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2769 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2770 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2771 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2772 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2773 m.texmatrix[2] = rsurface.entitytoattenuationz;
2774 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2775 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2776 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2777 R_Mesh_TextureState(&m);
2779 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2780 memset(&m, 0, sizeof(m));
2781 m.tex[0] = R_GetTexture(basetexture);
2782 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2783 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2784 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2785 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2786 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2787 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2788 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2789 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2790 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2791 R_Mesh_TextureState(&m);
2793 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2794 memset(&m, 0, sizeof(m));
2795 m.tex[0] = R_GetTexture(basetexture);
2796 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2797 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2798 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2799 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2800 R_Mesh_TextureState(&m);
2805 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2806 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2809 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2810 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2814 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2815 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2819 extern cvar_t gl_lightmaps;
2820 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)
2822 float ambientscale, diffusescale, specularscale;
2824 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2826 // calculate colors to render this texture with
2827 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2828 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2829 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2830 ambientscale = rsurface.rtlight->ambientscale;
2831 diffusescale = rsurface.rtlight->diffusescale;
2832 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2833 if (!r_shadow_usenormalmap.integer)
2835 ambientscale += 1.0f * diffusescale;
2839 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2841 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
2844 VectorNegate(lightcolorbase, lightcolorbase);
2845 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2847 RSurf_SetupDepthAndCulling();
2848 nmap = rsurface.texture->currentskinframe->nmap;
2849 if (gl_lightmaps.integer)
2850 nmap = r_texture_blanknormalmap;
2851 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2853 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2854 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2857 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2858 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2859 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2862 VectorClear(lightcolorpants);
2865 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2866 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2867 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2870 VectorClear(lightcolorshirt);
2871 switch (r_shadow_rendermode)
2873 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2874 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2875 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);
2877 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2878 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);
2880 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2881 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2882 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2883 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2884 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);
2887 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2893 switch (r_shadow_rendermode)
2895 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2896 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2897 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);
2899 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2900 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);
2902 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2903 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2904 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2905 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2906 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);
2909 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2914 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2917 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)
2919 matrix4x4_t tempmatrix = *matrix;
2920 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2922 // if this light has been compiled before, free the associated data
2923 R_RTLight_Uncompile(rtlight);
2925 // clear it completely to avoid any lingering data
2926 memset(rtlight, 0, sizeof(*rtlight));
2928 // copy the properties
2929 rtlight->matrix_lighttoworld = tempmatrix;
2930 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2931 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2932 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2933 VectorCopy(color, rtlight->color);
2934 rtlight->cubemapname[0] = 0;
2935 if (cubemapname && cubemapname[0])
2936 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2937 rtlight->shadow = shadow;
2938 rtlight->corona = corona;
2939 rtlight->style = style;
2940 rtlight->isstatic = isstatic;
2941 rtlight->coronasizescale = coronasizescale;
2942 rtlight->ambientscale = ambientscale;
2943 rtlight->diffusescale = diffusescale;
2944 rtlight->specularscale = specularscale;
2945 rtlight->flags = flags;
2947 // compute derived data
2948 //rtlight->cullradius = rtlight->radius;
2949 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2950 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2951 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2952 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2953 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2954 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2955 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2958 // compiles rtlight geometry
2959 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2960 void R_RTLight_Compile(rtlight_t *rtlight)
2963 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2964 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2965 entity_render_t *ent = r_refdef.scene.worldentity;
2966 dp_model_t *model = r_refdef.scene.worldmodel;
2967 unsigned char *data;
2970 // compile the light
2971 rtlight->compiled = true;
2972 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2973 rtlight->static_numleafs = 0;
2974 rtlight->static_numleafpvsbytes = 0;
2975 rtlight->static_leaflist = NULL;
2976 rtlight->static_leafpvs = NULL;
2977 rtlight->static_numsurfaces = 0;
2978 rtlight->static_surfacelist = NULL;
2979 rtlight->static_shadowmap_receivers = 0x3F;
2980 rtlight->static_shadowmap_casters = 0x3F;
2981 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2982 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2983 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2984 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2985 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2986 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2988 if (model && model->GetLightInfo)
2990 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2991 r_shadow_compilingrtlight = rtlight;
2992 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);
2993 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);
2994 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2995 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2996 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2997 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2998 rtlight->static_numsurfaces = numsurfaces;
2999 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3000 rtlight->static_numleafs = numleafs;
3001 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3002 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3003 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3004 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3005 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3006 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3007 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3008 if (rtlight->static_numsurfaces)
3009 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3010 if (rtlight->static_numleafs)
3011 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3012 if (rtlight->static_numleafpvsbytes)
3013 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3014 if (rtlight->static_numshadowtrispvsbytes)
3015 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3016 if (rtlight->static_numlighttrispvsbytes)
3017 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3018 switch (rtlight->shadowmode)
3020 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3021 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3022 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3023 if (model->CompileShadowMap && rtlight->shadow)
3024 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3027 if (model->CompileShadowVolume && rtlight->shadow)
3028 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3031 // now we're done compiling the rtlight
3032 r_shadow_compilingrtlight = NULL;
3036 // use smallest available cullradius - box radius or light radius
3037 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3038 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3040 shadowzpasstris = 0;
3041 if (rtlight->static_meshchain_shadow_zpass)
3042 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3043 shadowzpasstris += mesh->numtriangles;
3045 shadowzfailtris = 0;
3046 if (rtlight->static_meshchain_shadow_zfail)
3047 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3048 shadowzfailtris += mesh->numtriangles;
3051 if (rtlight->static_numlighttrispvsbytes)
3052 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3053 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3057 if (rtlight->static_numlighttrispvsbytes)
3058 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3059 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3062 if (developer.integer >= 10)
3063 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);
3066 void R_RTLight_Uncompile(rtlight_t *rtlight)
3068 if (rtlight->compiled)
3070 if (rtlight->static_meshchain_shadow_zpass)
3071 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3072 rtlight->static_meshchain_shadow_zpass = NULL;
3073 if (rtlight->static_meshchain_shadow_zfail)
3074 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3075 rtlight->static_meshchain_shadow_zfail = NULL;
3076 if (rtlight->static_meshchain_shadow_shadowmap)
3077 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3078 rtlight->static_meshchain_shadow_shadowmap = NULL;
3079 // these allocations are grouped
3080 if (rtlight->static_surfacelist)
3081 Mem_Free(rtlight->static_surfacelist);
3082 rtlight->static_numleafs = 0;
3083 rtlight->static_numleafpvsbytes = 0;
3084 rtlight->static_leaflist = NULL;
3085 rtlight->static_leafpvs = NULL;
3086 rtlight->static_numsurfaces = 0;
3087 rtlight->static_surfacelist = NULL;
3088 rtlight->static_numshadowtrispvsbytes = 0;
3089 rtlight->static_shadowtrispvs = NULL;
3090 rtlight->static_numlighttrispvsbytes = 0;
3091 rtlight->static_lighttrispvs = NULL;
3092 rtlight->compiled = false;
3096 void R_Shadow_UncompileWorldLights(void)
3100 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3101 for (lightindex = 0;lightindex < range;lightindex++)
3103 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3106 R_RTLight_Uncompile(&light->rtlight);
3110 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3114 // reset the count of frustum planes
3115 // see rsurface.rtlight_frustumplanes definition for how much this array
3117 rsurface.rtlight_numfrustumplanes = 0;
3119 // haven't implemented a culling path for ortho rendering
3120 if (!r_refdef.view.useperspective)
3122 // check if the light is on screen and copy the 4 planes if it is
3123 for (i = 0;i < 4;i++)
3124 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3127 for (i = 0;i < 4;i++)
3128 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3133 // generate a deformed frustum that includes the light origin, this is
3134 // used to cull shadow casting surfaces that can not possibly cast a
3135 // shadow onto the visible light-receiving surfaces, which can be a
3138 // if the light origin is onscreen the result will be 4 planes exactly
3139 // if the light origin is offscreen on only one axis the result will
3140 // be exactly 5 planes (split-side case)
3141 // if the light origin is offscreen on two axes the result will be
3142 // exactly 4 planes (stretched corner case)
3143 for (i = 0;i < 4;i++)
3145 // quickly reject standard frustum planes that put the light
3146 // origin outside the frustum
3147 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3150 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3152 // if all the standard frustum planes were accepted, the light is onscreen
3153 // otherwise we need to generate some more planes below...
3154 if (rsurface.rtlight_numfrustumplanes < 4)
3156 // at least one of the stock frustum planes failed, so we need to
3157 // create one or two custom planes to enclose the light origin
3158 for (i = 0;i < 4;i++)
3160 // create a plane using the view origin and light origin, and a
3161 // single point from the frustum corner set
3162 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3163 VectorNormalize(plane.normal);
3164 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3165 // see if this plane is backwards and flip it if so
3166 for (j = 0;j < 4;j++)
3167 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3171 VectorNegate(plane.normal, plane.normal);
3173 // flipped plane, test again to see if it is now valid
3174 for (j = 0;j < 4;j++)
3175 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3177 // if the plane is still not valid, then it is dividing the
3178 // frustum and has to be rejected
3182 // we have created a valid plane, compute extra info
3183 PlaneClassify(&plane);
3185 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3187 // if we've found 5 frustum planes then we have constructed a
3188 // proper split-side case and do not need to keep searching for
3189 // planes to enclose the light origin
3190 if (rsurface.rtlight_numfrustumplanes == 5)
3198 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3200 plane = rsurface.rtlight_frustumplanes[i];
3201 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));
3206 // now add the light-space box planes if the light box is rotated, as any
3207 // caster outside the oriented light box is irrelevant (even if it passed
3208 // the worldspace light box, which is axial)
3209 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3211 for (i = 0;i < 6;i++)
3215 v[i >> 1] = (i & 1) ? -1 : 1;
3216 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3217 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3218 plane.dist = VectorNormalizeLength(plane.normal);
3219 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3220 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3226 // add the world-space reduced box planes
3227 for (i = 0;i < 6;i++)
3229 VectorClear(plane.normal);
3230 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3231 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3232 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3241 // reduce all plane distances to tightly fit the rtlight cull box, which
3243 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3244 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3245 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3246 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3247 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3248 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3249 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3250 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3251 oldnum = rsurface.rtlight_numfrustumplanes;
3252 rsurface.rtlight_numfrustumplanes = 0;
3253 for (j = 0;j < oldnum;j++)
3255 // find the nearest point on the box to this plane
3256 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3257 for (i = 1;i < 8;i++)
3259 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3260 if (bestdist > dist)
3263 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);
3264 // if the nearest point is near or behind the plane, we want this
3265 // plane, otherwise the plane is useless as it won't cull anything
3266 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3268 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3269 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3276 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3280 RSurf_ActiveWorldEntity();
3282 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3285 GL_CullFace(GL_NONE);
3286 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3287 for (;mesh;mesh = mesh->next)
3289 if (!mesh->sidetotals[r_shadow_shadowmapside])
3291 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3292 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3293 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3297 else if (r_refdef.scene.worldentity->model)
3298 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);
3300 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3303 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3308 int surfacelistindex;
3309 msurface_t *surface;
3311 RSurf_ActiveWorldEntity();
3313 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3316 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3317 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3318 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3319 for (;mesh;mesh = mesh->next)
3321 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3322 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3323 GL_LockArrays(0, mesh->numverts);
3324 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3326 // increment stencil if frontface is infront of depthbuffer
3327 GL_CullFace(r_refdef.view.cullface_back);
3328 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3329 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3330 // decrement stencil if backface is infront of depthbuffer
3331 GL_CullFace(r_refdef.view.cullface_front);
3332 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3334 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3336 // decrement stencil if backface is behind depthbuffer
3337 GL_CullFace(r_refdef.view.cullface_front);
3338 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3339 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3340 // increment stencil if frontface is behind depthbuffer
3341 GL_CullFace(r_refdef.view.cullface_back);
3342 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3344 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3345 GL_LockArrays(0, 0);
3349 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3351 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3352 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3354 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3355 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3356 if (CHECKPVSBIT(trispvs, t))
3357 shadowmarklist[numshadowmark++] = t;
3359 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);
3361 else if (numsurfaces)
3362 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3364 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3367 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3369 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3370 vec_t relativeshadowradius;
3371 RSurf_ActiveModelEntity(ent, false, false);
3372 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3373 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3374 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3375 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3376 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3377 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3378 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3379 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3380 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3382 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3385 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3386 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3389 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3391 // set up properties for rendering light onto this entity
3392 RSurf_ActiveModelEntity(ent, true, true);
3393 GL_AlphaTest(false);
3394 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3395 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3396 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3397 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3398 switch(r_shadow_lightingrendermode)
3400 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3401 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3408 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3410 if (!r_refdef.scene.worldmodel->DrawLight)
3413 // set up properties for rendering light onto this entity
3414 RSurf_ActiveWorldEntity();
3415 GL_AlphaTest(false);
3416 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3417 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3418 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3419 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3420 switch(r_shadow_lightingrendermode)
3422 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3423 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3429 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3431 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3434 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3436 dp_model_t *model = ent->model;
3437 if (!model->DrawLight)
3440 R_Shadow_SetupEntityLight(ent);
3442 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3444 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3447 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3451 int numleafs, numsurfaces;
3452 int *leaflist, *surfacelist;
3453 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3454 int numlightentities;
3455 int numlightentities_noselfshadow;
3456 int numshadowentities;
3457 int numshadowentities_noselfshadow;
3458 static entity_render_t *lightentities[MAX_EDICTS];
3459 static entity_render_t *shadowentities[MAX_EDICTS];
3460 static unsigned char entitysides[MAX_EDICTS];
3461 int lightentities_noselfshadow;
3462 int shadowentities_noselfshadow;
3463 vec3_t nearestpoint;
3465 qboolean castshadows;
3468 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3469 // skip lights that are basically invisible (color 0 0 0)
3470 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3473 // loading is done before visibility checks because loading should happen
3474 // all at once at the start of a level, not when it stalls gameplay.
3475 // (especially important to benchmarks)
3477 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3479 if (rtlight->compiled)
3480 R_RTLight_Uncompile(rtlight);
3481 R_RTLight_Compile(rtlight);
3485 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3487 // look up the light style value at this time
3488 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3489 VectorScale(rtlight->color, f, rtlight->currentcolor);
3491 if (rtlight->selected)
3493 f = 2 + sin(realtime * M_PI * 4.0);
3494 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3498 // if lightstyle is currently off, don't draw the light
3499 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3502 // if the light box is offscreen, skip it
3503 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3506 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3507 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3509 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3511 // compiled light, world available and can receive realtime lighting
3512 // retrieve leaf information
3513 numleafs = rtlight->static_numleafs;
3514 leaflist = rtlight->static_leaflist;
3515 leafpvs = rtlight->static_leafpvs;
3516 numsurfaces = rtlight->static_numsurfaces;
3517 surfacelist = rtlight->static_surfacelist;
3518 surfacesides = NULL;
3519 shadowtrispvs = rtlight->static_shadowtrispvs;
3520 lighttrispvs = rtlight->static_lighttrispvs;
3522 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3524 // dynamic light, world available and can receive realtime lighting
3525 // calculate lit surfaces and leafs
3526 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);
3527 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);
3528 leaflist = r_shadow_buffer_leaflist;
3529 leafpvs = r_shadow_buffer_leafpvs;
3530 surfacelist = r_shadow_buffer_surfacelist;
3531 surfacesides = r_shadow_buffer_surfacesides;
3532 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3533 lighttrispvs = r_shadow_buffer_lighttrispvs;
3534 // if the reduced leaf bounds are offscreen, skip it
3535 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3546 surfacesides = NULL;
3547 shadowtrispvs = NULL;
3548 lighttrispvs = NULL;
3550 // check if light is illuminating any visible leafs
3553 for (i = 0;i < numleafs;i++)
3554 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3559 // set up a scissor rectangle for this light
3560 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3563 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3565 // make a list of lit entities and shadow casting entities
3566 numlightentities = 0;
3567 numlightentities_noselfshadow = 0;
3568 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
3569 numshadowentities = 0;
3570 numshadowentities_noselfshadow = 0;
3571 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
3573 // add dynamic entities that are lit by the light
3574 if (r_drawentities.integer)
3576 for (i = 0;i < r_refdef.scene.numentities;i++)
3579 entity_render_t *ent = r_refdef.scene.entities[i];
3581 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3583 // skip the object entirely if it is not within the valid
3584 // shadow-casting region (which includes the lit region)
3585 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3587 if (!(model = ent->model))
3589 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3591 // this entity wants to receive light, is visible, and is
3592 // inside the light box
3593 // TODO: check if the surfaces in the model can receive light
3594 // so now check if it's in a leaf seen by the light
3595 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))
3597 if (ent->flags & RENDER_NOSELFSHADOW)
3598 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
3600 lightentities[numlightentities++] = ent;
3601 // since it is lit, it probably also casts a shadow...
3602 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3603 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3604 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3606 // note: exterior models without the RENDER_NOSELFSHADOW
3607 // flag still create a RENDER_NOSELFSHADOW shadow but
3608 // are lit normally, this means that they are
3609 // self-shadowing but do not shadow other
3610 // RENDER_NOSELFSHADOW entities such as the gun
3611 // (very weird, but keeps the player shadow off the gun)
3612 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3613 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
3615 shadowentities[numshadowentities++] = ent;
3618 else if (ent->flags & RENDER_SHADOW)
3620 // this entity is not receiving light, but may still need to
3622 // TODO: check if the surfaces in the model can cast shadow
3623 // now check if it is in a leaf seen by the light
3624 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))
3626 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3627 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3628 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3630 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3631 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
3633 shadowentities[numshadowentities++] = ent;
3639 // return if there's nothing at all to light
3640 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3643 // don't let sound skip if going slow
3644 if (r_refdef.scene.extraupdate)
3647 // make this the active rtlight for rendering purposes
3648 R_Shadow_RenderMode_ActiveLight(rtlight);
3649 // count this light in the r_speeds
3650 r_refdef.stats.lights++;
3652 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3654 // optionally draw visible shape of the shadow volumes
3655 // for performance analysis by level designers
3656 R_Shadow_RenderMode_VisibleShadowVolumes();
3658 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3659 for (i = 0;i < numshadowentities;i++)
3660 R_Shadow_DrawEntityShadow(shadowentities[i]);
3661 for (i = 0;i < numshadowentities_noselfshadow;i++)
3662 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3665 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3667 // optionally draw the illuminated areas
3668 // for performance analysis by level designers
3669 R_Shadow_RenderMode_VisibleLighting(false, false);
3671 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3672 for (i = 0;i < numlightentities;i++)
3673 R_Shadow_DrawEntityLight(lightentities[i]);
3674 for (i = 0;i < numlightentities_noselfshadow;i++)
3675 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3678 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3680 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3681 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3682 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3683 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3685 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3686 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3687 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3689 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3695 int receivermask = 0;
3696 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3697 Matrix4x4_Abs(&radiustolight);
3699 r_shadow_shadowmaplod = 0;
3700 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3701 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3702 r_shadow_shadowmaplod = i;
3704 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3705 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3707 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3709 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3713 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3715 castermask = rtlight->static_shadowmap_casters;
3716 receivermask = rtlight->static_shadowmap_receivers;
3720 for(i = 0;i < numsurfaces;i++)
3722 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3723 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3724 castermask |= surfacesides[i];
3725 receivermask |= surfacesides[i];
3729 if (receivermask < 0x3F)
3731 for (i = 0;i < numlightentities;i++)
3732 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3733 if (receivermask < 0x3F)
3734 for(i = 0; i < numlightentities_noselfshadow;i++)
3735 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3738 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3742 for (i = 0;i < numshadowentities;i++)
3743 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3744 for (i = 0;i < numshadowentities_noselfshadow;i++)
3745 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3748 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3750 // render shadow casters into 6 sided depth texture
3751 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3753 R_Shadow_RenderMode_ShadowMap(side, true, size);
3754 if (! (castermask & (1 << side))) continue;
3756 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3757 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3758 R_Shadow_DrawEntityShadow(shadowentities[i]);
3761 if (numlightentities_noselfshadow)
3763 // render lighting using the depth texture as shadowmap
3764 // draw lighting in the unmasked areas
3765 R_Shadow_RenderMode_Lighting(false, false, true);
3766 for (i = 0;i < numlightentities_noselfshadow;i++)
3767 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3770 // render shadow casters into 6 sided depth texture
3771 if (numshadowentities_noselfshadow)
3773 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3775 R_Shadow_RenderMode_ShadowMap(side, false, size);
3776 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
3777 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3781 // render lighting using the depth texture as shadowmap
3782 // draw lighting in the unmasked areas
3783 R_Shadow_RenderMode_Lighting(false, false, true);
3784 // draw lighting in the unmasked areas
3786 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3787 for (i = 0;i < numlightentities;i++)
3788 R_Shadow_DrawEntityLight(lightentities[i]);
3790 else if (castshadows && vid.stencil)
3792 // draw stencil shadow volumes to mask off pixels that are in shadow
3793 // so that they won't receive lighting
3794 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3795 R_Shadow_ClearStencil();
3797 if (numsurfaces + numshadowentities)
3800 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3801 for (i = 0;i < numshadowentities;i++)
3802 R_Shadow_DrawEntityShadow(shadowentities[i]);
3805 if (numlightentities_noselfshadow)
3807 // draw lighting in the unmasked areas
3808 R_Shadow_RenderMode_Lighting(true, false, false);
3809 for (i = 0;i < numlightentities_noselfshadow;i++)
3810 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3812 // optionally draw the illuminated areas
3813 // for performance analysis by level designers
3814 if (r_showlighting.integer && r_refdef.view.showdebug)
3816 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3817 for (i = 0;i < numlightentities_noselfshadow;i++)
3818 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3820 for (i = 0;i < numshadowentities_noselfshadow;i++)
3821 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
3824 if (numsurfaces + numlightentities)
3826 // draw lighting in the unmasked areas
3827 R_Shadow_RenderMode_Lighting(true, false, false);
3829 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3830 for (i = 0;i < numlightentities;i++)
3831 R_Shadow_DrawEntityLight(lightentities[i]);
3836 // draw lighting in the unmasked areas
3837 R_Shadow_RenderMode_Lighting(false, false, false);
3839 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3840 for (i = 0;i < numlightentities;i++)
3841 R_Shadow_DrawEntityLight(lightentities[i]);
3842 for (i = 0;i < numlightentities_noselfshadow;i++)
3843 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
3847 void R_Shadow_DrawLightSprites(void);
3848 void R_ShadowVolumeLighting(qboolean visible)
3857 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3858 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != r_shadow_shadowmapping.integer ||
3859 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3860 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3861 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3862 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3863 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3864 R_Shadow_FreeShadowMaps();
3866 if (r_editlights.integer)
3867 R_Shadow_DrawLightSprites();
3869 R_Shadow_RenderMode_Begin();
3871 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3872 if (r_shadow_debuglight.integer >= 0)
3874 lightindex = r_shadow_debuglight.integer;
3875 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3876 if (light && (light->flags & flag))
3877 R_DrawRTLight(&light->rtlight, visible);
3881 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3882 for (lightindex = 0;lightindex < range;lightindex++)
3884 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3885 if (light && (light->flags & flag))
3886 R_DrawRTLight(&light->rtlight, visible);
3889 if (r_refdef.scene.rtdlight)
3891 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3892 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3894 else if(gl_flashblend.integer)
3896 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3898 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3899 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3900 VectorScale(rtlight->color, f, rtlight->currentcolor);
3904 R_Shadow_RenderMode_End();
3907 extern const float r_screenvertex3f[12];
3908 extern void R_SetupView(qboolean allowwaterclippingplane);
3909 extern void R_ResetViewRendering3D(void);
3910 extern void R_ResetViewRendering2D(void);
3911 extern cvar_t r_shadows;
3912 extern cvar_t r_shadows_darken;
3913 extern cvar_t r_shadows_drawafterrtlighting;
3914 extern cvar_t r_shadows_castfrombmodels;
3915 extern cvar_t r_shadows_throwdistance;
3916 extern cvar_t r_shadows_throwdirection;
3917 void R_DrawModelShadows(void)
3920 float relativethrowdistance;
3921 entity_render_t *ent;
3922 vec3_t relativelightorigin;
3923 vec3_t relativelightdirection;
3924 vec3_t relativeshadowmins, relativeshadowmaxs;
3925 vec3_t tmp, shadowdir;
3927 if (!r_drawentities.integer || !vid.stencil)
3931 R_ResetViewRendering3D();
3932 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3933 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3934 R_Shadow_RenderMode_Begin();
3935 R_Shadow_RenderMode_ActiveLight(NULL);
3936 r_shadow_lightscissor[0] = r_refdef.view.x;
3937 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3938 r_shadow_lightscissor[2] = r_refdef.view.width;
3939 r_shadow_lightscissor[3] = r_refdef.view.height;
3940 R_Shadow_RenderMode_StencilShadowVolumes(false);
3943 if (r_shadows.integer == 2)
3945 Math_atov(r_shadows_throwdirection.string, shadowdir);
3946 VectorNormalize(shadowdir);
3949 R_Shadow_ClearStencil();
3951 for (i = 0;i < r_refdef.scene.numentities;i++)
3953 ent = r_refdef.scene.entities[i];
3955 // cast shadows from anything of the map (submodels are optional)
3956 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3958 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3959 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3960 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3961 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3962 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3965 if(ent->entitynumber != 0)
3967 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3968 int entnum, entnum2, recursion;
3969 entnum = entnum2 = ent->entitynumber;
3970 for(recursion = 32; recursion > 0; --recursion)
3972 entnum2 = cl.entities[entnum].state_current.tagentity;
3973 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3978 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3980 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3981 // transform into modelspace of OUR entity
3982 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3983 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3986 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3989 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3992 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3993 RSurf_ActiveModelEntity(ent, false, false);
3994 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3995 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3999 // not really the right mode, but this will disable any silly stencil features
4000 R_Shadow_RenderMode_End();
4002 // set up ortho view for rendering this pass
4003 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4004 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4005 //GL_ScissorTest(true);
4006 //R_Mesh_Matrix(&identitymatrix);
4007 //R_Mesh_ResetTextureState();
4008 R_ResetViewRendering2D();
4009 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4010 R_Mesh_ColorPointer(NULL, 0, 0);
4011 R_SetupGenericShader(false);
4013 // set up a darkening blend on shadowed areas
4014 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4015 //GL_DepthRange(0, 1);
4016 //GL_DepthTest(false);
4017 //GL_DepthMask(false);
4018 //GL_PolygonOffset(0, 0);CHECKGLERROR
4019 GL_Color(0, 0, 0, r_shadows_darken.value);
4020 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4021 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4022 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4023 qglStencilMask(~0);CHECKGLERROR
4024 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4025 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4027 // apply the blend to the shadowed areas
4028 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4030 // restore the viewport
4031 R_SetViewport(&r_refdef.view.viewport);
4033 // restore other state to normal
4034 //R_Shadow_RenderMode_End();
4037 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4040 vec3_t centerorigin;
4042 // if it's too close, skip it
4043 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4045 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4048 if (usequery && r_numqueries + 2 <= r_maxqueries)
4050 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4051 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4052 // 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
4053 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4056 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4057 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4058 qglDepthFunc(GL_ALWAYS);
4059 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4060 R_Mesh_VertexPointer(vertex3f, 0, 0);
4061 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4062 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4063 qglDepthFunc(GL_LEQUAL);
4064 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4065 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4066 R_Mesh_VertexPointer(vertex3f, 0, 0);
4067 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4068 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4071 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4074 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4076 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4079 GLint allpixels = 0, visiblepixels = 0;
4080 // now we have to check the query result
4081 if (rtlight->corona_queryindex_visiblepixels)
4084 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4085 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4087 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4088 if (visiblepixels < 1 || allpixels < 1)
4090 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4091 cscale *= rtlight->corona_visibility;
4095 // FIXME: these traces should scan all render entities instead of cl.world
4096 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4099 VectorScale(rtlight->currentcolor, cscale, color);
4100 if (VectorLength(color) > (1.0f / 256.0f))
4103 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4106 VectorNegate(color, color);
4107 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4109 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4110 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);
4111 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4113 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4117 void R_DrawCoronas(void)
4125 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4127 if (r_waterstate.renderingscene)
4129 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4130 R_Mesh_Matrix(&identitymatrix);
4132 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4134 // check occlusion of coronas
4135 // use GL_ARB_occlusion_query if available
4136 // otherwise use raytraces
4138 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4141 GL_ColorMask(0,0,0,0);
4142 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4143 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4146 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4147 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4149 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4152 RSurf_ActiveWorldEntity();
4153 GL_BlendFunc(GL_ONE, GL_ZERO);
4154 GL_CullFace(GL_NONE);
4155 GL_DepthMask(false);
4156 GL_DepthRange(0, 1);
4157 GL_PolygonOffset(0, 0);
4159 R_Mesh_ColorPointer(NULL, 0, 0);
4160 R_Mesh_ResetTextureState();
4161 R_SetupGenericShader(false);
4163 for (lightindex = 0;lightindex < range;lightindex++)
4165 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4168 rtlight = &light->rtlight;
4169 rtlight->corona_visibility = 0;
4170 rtlight->corona_queryindex_visiblepixels = 0;
4171 rtlight->corona_queryindex_allpixels = 0;
4172 if (!(rtlight->flags & flag))
4174 if (rtlight->corona <= 0)
4176 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4178 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4180 for (i = 0;i < r_refdef.scene.numlights;i++)
4182 rtlight = r_refdef.scene.lights[i];
4183 rtlight->corona_visibility = 0;
4184 rtlight->corona_queryindex_visiblepixels = 0;
4185 rtlight->corona_queryindex_allpixels = 0;
4186 if (!(rtlight->flags & flag))
4188 if (rtlight->corona <= 0)
4190 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4193 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4195 // now draw the coronas using the query data for intensity info
4196 for (lightindex = 0;lightindex < range;lightindex++)
4198 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4201 rtlight = &light->rtlight;
4202 if (rtlight->corona_visibility <= 0)
4204 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4206 for (i = 0;i < r_refdef.scene.numlights;i++)
4208 rtlight = r_refdef.scene.lights[i];
4209 if (rtlight->corona_visibility <= 0)
4211 if (gl_flashblend.integer)
4212 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4214 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4220 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4221 typedef struct suffixinfo_s
4224 qboolean flipx, flipy, flipdiagonal;
4227 static suffixinfo_t suffix[3][6] =
4230 {"px", false, false, false},
4231 {"nx", false, false, false},
4232 {"py", false, false, false},
4233 {"ny", false, false, false},
4234 {"pz", false, false, false},
4235 {"nz", false, false, false}
4238 {"posx", false, false, false},
4239 {"negx", false, false, false},
4240 {"posy", false, false, false},
4241 {"negy", false, false, false},
4242 {"posz", false, false, false},
4243 {"negz", false, false, false}
4246 {"rt", true, false, true},
4247 {"lf", false, true, true},
4248 {"ft", true, true, false},
4249 {"bk", false, false, false},
4250 {"up", true, false, true},
4251 {"dn", true, false, true}
4255 static int componentorder[4] = {0, 1, 2, 3};
4257 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4259 int i, j, cubemapsize;
4260 unsigned char *cubemappixels, *image_buffer;
4261 rtexture_t *cubemaptexture;
4263 // must start 0 so the first loadimagepixels has no requested width/height
4265 cubemappixels = NULL;
4266 cubemaptexture = NULL;
4267 // keep trying different suffix groups (posx, px, rt) until one loads
4268 for (j = 0;j < 3 && !cubemappixels;j++)
4270 // load the 6 images in the suffix group
4271 for (i = 0;i < 6;i++)
4273 // generate an image name based on the base and and suffix
4274 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4276 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4278 // an image loaded, make sure width and height are equal
4279 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4281 // if this is the first image to load successfully, allocate the cubemap memory
4282 if (!cubemappixels && image_width >= 1)
4284 cubemapsize = image_width;
4285 // note this clears to black, so unavailable sides are black
4286 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4288 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4290 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);
4293 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4295 Mem_Free(image_buffer);
4299 // if a cubemap loaded, upload it
4302 if (developer_loading.integer)
4303 Con_Printf("loading cubemap \"%s\"\n", basename);
4305 if (!r_shadow_filters_texturepool)
4306 r_shadow_filters_texturepool = R_AllocTexturePool();
4307 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4308 Mem_Free(cubemappixels);
4312 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4313 if (developer_loading.integer)
4315 Con_Printf("(tried tried images ");
4316 for (j = 0;j < 3;j++)
4317 for (i = 0;i < 6;i++)
4318 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4319 Con_Print(" and was unable to find any of them).\n");
4322 return cubemaptexture;
4325 rtexture_t *R_Shadow_Cubemap(const char *basename)
4328 for (i = 0;i < numcubemaps;i++)
4329 if (!strcasecmp(cubemaps[i].basename, basename))
4330 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4331 if (i >= MAX_CUBEMAPS)
4332 return r_texture_whitecube;
4334 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4335 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4336 return cubemaps[i].texture;
4339 void R_Shadow_FreeCubemaps(void)
4342 for (i = 0;i < numcubemaps;i++)
4344 if (developer_loading.integer)
4345 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4346 if (cubemaps[i].texture)
4347 R_FreeTexture(cubemaps[i].texture);
4351 R_FreeTexturePool(&r_shadow_filters_texturepool);
4354 dlight_t *R_Shadow_NewWorldLight(void)
4356 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4359 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)
4362 // validate parameters
4363 if (style < 0 || style >= MAX_LIGHTSTYLES)
4365 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4371 // copy to light properties
4372 VectorCopy(origin, light->origin);
4373 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4374 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4375 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4377 light->color[0] = max(color[0], 0);
4378 light->color[1] = max(color[1], 0);
4379 light->color[2] = max(color[2], 0);
4381 light->color[0] = color[0];
4382 light->color[1] = color[1];
4383 light->color[2] = color[2];
4384 light->radius = max(radius, 0);
4385 light->style = style;
4386 light->shadow = shadowenable;
4387 light->corona = corona;
4388 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4389 light->coronasizescale = coronasizescale;
4390 light->ambientscale = ambientscale;
4391 light->diffusescale = diffusescale;
4392 light->specularscale = specularscale;
4393 light->flags = flags;
4395 // update renderable light data
4396 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4397 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);
4400 void R_Shadow_FreeWorldLight(dlight_t *light)
4402 if (r_shadow_selectedlight == light)
4403 r_shadow_selectedlight = NULL;
4404 R_RTLight_Uncompile(&light->rtlight);
4405 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4408 void R_Shadow_ClearWorldLights(void)
4412 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4413 for (lightindex = 0;lightindex < range;lightindex++)
4415 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4417 R_Shadow_FreeWorldLight(light);
4419 r_shadow_selectedlight = NULL;
4420 R_Shadow_FreeCubemaps();
4423 void R_Shadow_SelectLight(dlight_t *light)
4425 if (r_shadow_selectedlight)
4426 r_shadow_selectedlight->selected = false;
4427 r_shadow_selectedlight = light;
4428 if (r_shadow_selectedlight)
4429 r_shadow_selectedlight->selected = true;
4432 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4434 // this is never batched (there can be only one)
4436 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4437 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4438 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4441 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4446 skinframe_t *skinframe;
4449 // this is never batched (due to the ent parameter changing every time)
4450 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4451 const dlight_t *light = (dlight_t *)ent;
4454 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4457 VectorScale(light->color, intensity, spritecolor);
4458 if (VectorLength(spritecolor) < 0.1732f)
4459 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4460 if (VectorLength(spritecolor) > 1.0f)
4461 VectorNormalize(spritecolor);
4463 // draw light sprite
4464 if (light->cubemapname[0] && !light->shadow)
4465 skinframe = r_editlights_sprcubemapnoshadowlight;
4466 else if (light->cubemapname[0])
4467 skinframe = r_editlights_sprcubemaplight;
4468 else if (!light->shadow)
4469 skinframe = r_editlights_sprnoshadowlight;
4471 skinframe = r_editlights_sprlight;
4473 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);
4474 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4476 // draw selection sprite if light is selected
4477 if (light->selected)
4479 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4480 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4481 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4485 void R_Shadow_DrawLightSprites(void)
4489 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4490 for (lightindex = 0;lightindex < range;lightindex++)
4492 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4494 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4496 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4499 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4504 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4505 if (lightindex >= range)
4507 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4510 rtlight = &light->rtlight;
4511 //if (!(rtlight->flags & flag))
4513 VectorCopy(rtlight->shadoworigin, origin);
4514 *radius = rtlight->radius;
4515 VectorCopy(rtlight->color, color);
4519 void R_Shadow_SelectLightInView(void)
4521 float bestrating, rating, temp[3];
4525 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4528 for (lightindex = 0;lightindex < range;lightindex++)
4530 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4533 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4534 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4537 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4538 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4540 bestrating = rating;
4545 R_Shadow_SelectLight(best);
4548 void R_Shadow_LoadWorldLights(void)
4550 int n, a, style, shadow, flags;
4551 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4552 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4553 if (cl.worldmodel == NULL)
4555 Con_Print("No map loaded.\n");
4558 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4559 strlcat (name, ".rtlights", sizeof (name));
4560 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4570 for (;COM_Parse(t, true) && strcmp(
4571 if (COM_Parse(t, true))
4573 if (com_token[0] == '!')
4576 origin[0] = atof(com_token+1);
4579 origin[0] = atof(com_token);
4584 while (*s && *s != '\n' && *s != '\r')
4590 // check for modifier flags
4597 #if _MSC_VER >= 1400
4598 #define sscanf sscanf_s
4600 cubemapname[sizeof(cubemapname)-1] = 0;
4601 #if MAX_QPATH != 128
4602 #error update this code if MAX_QPATH changes
4604 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
4605 #if _MSC_VER >= 1400
4606 , sizeof(cubemapname)
4608 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4611 flags = LIGHTFLAG_REALTIMEMODE;
4619 coronasizescale = 0.25f;
4621 VectorClear(angles);
4624 if (a < 9 || !strcmp(cubemapname, "\"\""))
4626 // remove quotes on cubemapname
4627 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4630 namelen = strlen(cubemapname) - 2;
4631 memmove(cubemapname, cubemapname + 1, namelen);
4632 cubemapname[namelen] = '\0';
4636 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);
4639 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4647 Con_Printf("invalid rtlights file \"%s\"\n", name);
4648 Mem_Free(lightsstring);
4652 void R_Shadow_SaveWorldLights(void)
4656 size_t bufchars, bufmaxchars;
4658 char name[MAX_QPATH];
4659 char line[MAX_INPUTLINE];
4660 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4661 // I hate lines which are 3 times my screen size :( --blub
4664 if (cl.worldmodel == NULL)
4666 Con_Print("No map loaded.\n");
4669 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4670 strlcat (name, ".rtlights", sizeof (name));
4671 bufchars = bufmaxchars = 0;
4673 for (lightindex = 0;lightindex < range;lightindex++)
4675 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4678 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4679 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);
4680 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4681 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]);
4683 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);
4684 if (bufchars + strlen(line) > bufmaxchars)
4686 bufmaxchars = bufchars + strlen(line) + 2048;
4688 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4692 memcpy(buf, oldbuf, bufchars);
4698 memcpy(buf + bufchars, line, strlen(line));
4699 bufchars += strlen(line);
4703 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4708 void R_Shadow_LoadLightsFile(void)
4711 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4712 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4713 if (cl.worldmodel == NULL)
4715 Con_Print("No map loaded.\n");
4718 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4719 strlcat (name, ".lights", sizeof (name));
4720 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4728 while (*s && *s != '\n' && *s != '\r')
4734 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);
4738 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);
4741 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4742 radius = bound(15, radius, 4096);
4743 VectorScale(color, (2.0f / (8388608.0f)), color);
4744 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4752 Con_Printf("invalid lights file \"%s\"\n", name);
4753 Mem_Free(lightsstring);
4757 // tyrlite/hmap2 light types in the delay field
4758 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4760 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4762 int entnum, style, islight, skin, pflags, effects, type, n;
4765 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4766 char key[256], value[MAX_INPUTLINE];
4768 if (cl.worldmodel == NULL)
4770 Con_Print("No map loaded.\n");
4773 // try to load a .ent file first
4774 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4775 strlcat (key, ".ent", sizeof (key));
4776 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4777 // and if that is not found, fall back to the bsp file entity string
4779 data = cl.worldmodel->brush.entities;
4782 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4784 type = LIGHTTYPE_MINUSX;
4785 origin[0] = origin[1] = origin[2] = 0;
4786 originhack[0] = originhack[1] = originhack[2] = 0;
4787 angles[0] = angles[1] = angles[2] = 0;
4788 color[0] = color[1] = color[2] = 1;
4789 light[0] = light[1] = light[2] = 1;light[3] = 300;
4790 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4800 if (!COM_ParseToken_Simple(&data, false, false))
4802 if (com_token[0] == '}')
4803 break; // end of entity
4804 if (com_token[0] == '_')
4805 strlcpy(key, com_token + 1, sizeof(key));
4807 strlcpy(key, com_token, sizeof(key));
4808 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4809 key[strlen(key)-1] = 0;
4810 if (!COM_ParseToken_Simple(&data, false, false))
4812 strlcpy(value, com_token, sizeof(value));
4814 // now that we have the key pair worked out...
4815 if (!strcmp("light", key))
4817 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4821 light[0] = vec[0] * (1.0f / 256.0f);
4822 light[1] = vec[0] * (1.0f / 256.0f);
4823 light[2] = vec[0] * (1.0f / 256.0f);
4829 light[0] = vec[0] * (1.0f / 255.0f);
4830 light[1] = vec[1] * (1.0f / 255.0f);
4831 light[2] = vec[2] * (1.0f / 255.0f);
4835 else if (!strcmp("delay", key))
4837 else if (!strcmp("origin", key))
4838 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4839 else if (!strcmp("angle", key))
4840 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4841 else if (!strcmp("angles", key))
4842 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4843 else if (!strcmp("color", key))
4844 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4845 else if (!strcmp("wait", key))
4846 fadescale = atof(value);
4847 else if (!strcmp("classname", key))
4849 if (!strncmp(value, "light", 5))
4852 if (!strcmp(value, "light_fluoro"))
4857 overridecolor[0] = 1;
4858 overridecolor[1] = 1;
4859 overridecolor[2] = 1;
4861 if (!strcmp(value, "light_fluorospark"))
4866 overridecolor[0] = 1;
4867 overridecolor[1] = 1;
4868 overridecolor[2] = 1;
4870 if (!strcmp(value, "light_globe"))
4875 overridecolor[0] = 1;
4876 overridecolor[1] = 0.8;
4877 overridecolor[2] = 0.4;
4879 if (!strcmp(value, "light_flame_large_yellow"))
4884 overridecolor[0] = 1;
4885 overridecolor[1] = 0.5;
4886 overridecolor[2] = 0.1;
4888 if (!strcmp(value, "light_flame_small_yellow"))
4893 overridecolor[0] = 1;
4894 overridecolor[1] = 0.5;
4895 overridecolor[2] = 0.1;
4897 if (!strcmp(value, "light_torch_small_white"))
4902 overridecolor[0] = 1;
4903 overridecolor[1] = 0.5;
4904 overridecolor[2] = 0.1;
4906 if (!strcmp(value, "light_torch_small_walltorch"))
4911 overridecolor[0] = 1;
4912 overridecolor[1] = 0.5;
4913 overridecolor[2] = 0.1;
4917 else if (!strcmp("style", key))
4918 style = atoi(value);
4919 else if (!strcmp("skin", key))
4920 skin = (int)atof(value);
4921 else if (!strcmp("pflags", key))
4922 pflags = (int)atof(value);
4923 else if (!strcmp("effects", key))
4924 effects = (int)atof(value);
4925 else if (cl.worldmodel->type == mod_brushq3)
4927 if (!strcmp("scale", key))
4928 lightscale = atof(value);
4929 if (!strcmp("fade", key))
4930 fadescale = atof(value);
4935 if (lightscale <= 0)
4939 if (color[0] == color[1] && color[0] == color[2])
4941 color[0] *= overridecolor[0];
4942 color[1] *= overridecolor[1];
4943 color[2] *= overridecolor[2];
4945 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4946 color[0] = color[0] * light[0];
4947 color[1] = color[1] * light[1];
4948 color[2] = color[2] * light[2];
4951 case LIGHTTYPE_MINUSX:
4953 case LIGHTTYPE_RECIPX:
4955 VectorScale(color, (1.0f / 16.0f), color);
4957 case LIGHTTYPE_RECIPXX:
4959 VectorScale(color, (1.0f / 16.0f), color);
4962 case LIGHTTYPE_NONE:
4966 case LIGHTTYPE_MINUSXX:
4969 VectorAdd(origin, originhack, origin);
4971 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);
4974 Mem_Free(entfiledata);
4978 void R_Shadow_SetCursorLocationForView(void)
4981 vec3_t dest, endpos;
4983 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4984 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4985 if (trace.fraction < 1)
4987 dist = trace.fraction * r_editlights_cursordistance.value;
4988 push = r_editlights_cursorpushback.value;
4992 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4993 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4997 VectorClear( endpos );
4999 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5000 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5001 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5004 void R_Shadow_UpdateWorldLightSelection(void)
5006 if (r_editlights.integer)
5008 R_Shadow_SetCursorLocationForView();
5009 R_Shadow_SelectLightInView();
5012 R_Shadow_SelectLight(NULL);
5015 void R_Shadow_EditLights_Clear_f(void)
5017 R_Shadow_ClearWorldLights();
5020 void R_Shadow_EditLights_Reload_f(void)
5024 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5025 R_Shadow_ClearWorldLights();
5026 R_Shadow_LoadWorldLights();
5027 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5029 R_Shadow_LoadLightsFile();
5030 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5031 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5035 void R_Shadow_EditLights_Save_f(void)
5039 R_Shadow_SaveWorldLights();
5042 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5044 R_Shadow_ClearWorldLights();
5045 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5048 void R_Shadow_EditLights_ImportLightsFile_f(void)
5050 R_Shadow_ClearWorldLights();
5051 R_Shadow_LoadLightsFile();
5054 void R_Shadow_EditLights_Spawn_f(void)
5057 if (!r_editlights.integer)
5059 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5062 if (Cmd_Argc() != 1)
5064 Con_Print("r_editlights_spawn does not take parameters\n");
5067 color[0] = color[1] = color[2] = 1;
5068 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5071 void R_Shadow_EditLights_Edit_f(void)
5073 vec3_t origin, angles, color;
5074 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5075 int style, shadows, flags, normalmode, realtimemode;
5076 char cubemapname[MAX_INPUTLINE];
5077 if (!r_editlights.integer)
5079 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5082 if (!r_shadow_selectedlight)
5084 Con_Print("No selected light.\n");
5087 VectorCopy(r_shadow_selectedlight->origin, origin);
5088 VectorCopy(r_shadow_selectedlight->angles, angles);
5089 VectorCopy(r_shadow_selectedlight->color, color);
5090 radius = r_shadow_selectedlight->radius;
5091 style = r_shadow_selectedlight->style;
5092 if (r_shadow_selectedlight->cubemapname)
5093 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5096 shadows = r_shadow_selectedlight->shadow;
5097 corona = r_shadow_selectedlight->corona;
5098 coronasizescale = r_shadow_selectedlight->coronasizescale;
5099 ambientscale = r_shadow_selectedlight->ambientscale;
5100 diffusescale = r_shadow_selectedlight->diffusescale;
5101 specularscale = r_shadow_selectedlight->specularscale;
5102 flags = r_shadow_selectedlight->flags;
5103 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5104 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5105 if (!strcmp(Cmd_Argv(1), "origin"))
5107 if (Cmd_Argc() != 5)
5109 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5112 origin[0] = atof(Cmd_Argv(2));
5113 origin[1] = atof(Cmd_Argv(3));
5114 origin[2] = atof(Cmd_Argv(4));
5116 else if (!strcmp(Cmd_Argv(1), "originx"))
5118 if (Cmd_Argc() != 3)
5120 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5123 origin[0] = atof(Cmd_Argv(2));
5125 else if (!strcmp(Cmd_Argv(1), "originy"))
5127 if (Cmd_Argc() != 3)
5129 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5132 origin[1] = atof(Cmd_Argv(2));
5134 else if (!strcmp(Cmd_Argv(1), "originz"))
5136 if (Cmd_Argc() != 3)
5138 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5141 origin[2] = atof(Cmd_Argv(2));
5143 else if (!strcmp(Cmd_Argv(1), "move"))
5145 if (Cmd_Argc() != 5)
5147 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5150 origin[0] += atof(Cmd_Argv(2));
5151 origin[1] += atof(Cmd_Argv(3));
5152 origin[2] += atof(Cmd_Argv(4));
5154 else if (!strcmp(Cmd_Argv(1), "movex"))
5156 if (Cmd_Argc() != 3)
5158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5161 origin[0] += atof(Cmd_Argv(2));
5163 else if (!strcmp(Cmd_Argv(1), "movey"))
5165 if (Cmd_Argc() != 3)
5167 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5170 origin[1] += atof(Cmd_Argv(2));
5172 else if (!strcmp(Cmd_Argv(1), "movez"))
5174 if (Cmd_Argc() != 3)
5176 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5179 origin[2] += atof(Cmd_Argv(2));
5181 else if (!strcmp(Cmd_Argv(1), "angles"))
5183 if (Cmd_Argc() != 5)
5185 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5188 angles[0] = atof(Cmd_Argv(2));
5189 angles[1] = atof(Cmd_Argv(3));
5190 angles[2] = atof(Cmd_Argv(4));
5192 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5194 if (Cmd_Argc() != 3)
5196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5199 angles[0] = atof(Cmd_Argv(2));
5201 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5203 if (Cmd_Argc() != 3)
5205 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5208 angles[1] = atof(Cmd_Argv(2));
5210 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5212 if (Cmd_Argc() != 3)
5214 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5217 angles[2] = atof(Cmd_Argv(2));
5219 else if (!strcmp(Cmd_Argv(1), "color"))
5221 if (Cmd_Argc() != 5)
5223 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5226 color[0] = atof(Cmd_Argv(2));
5227 color[1] = atof(Cmd_Argv(3));
5228 color[2] = atof(Cmd_Argv(4));
5230 else if (!strcmp(Cmd_Argv(1), "radius"))
5232 if (Cmd_Argc() != 3)
5234 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5237 radius = atof(Cmd_Argv(2));
5239 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5241 if (Cmd_Argc() == 3)
5243 double scale = atof(Cmd_Argv(2));
5250 if (Cmd_Argc() != 5)
5252 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5255 color[0] *= atof(Cmd_Argv(2));
5256 color[1] *= atof(Cmd_Argv(3));
5257 color[2] *= atof(Cmd_Argv(4));
5260 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5262 if (Cmd_Argc() != 3)
5264 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5267 radius *= atof(Cmd_Argv(2));
5269 else if (!strcmp(Cmd_Argv(1), "style"))
5271 if (Cmd_Argc() != 3)
5273 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5276 style = atoi(Cmd_Argv(2));
5278 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5282 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5285 if (Cmd_Argc() == 3)
5286 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5290 else if (!strcmp(Cmd_Argv(1), "shadows"))
5292 if (Cmd_Argc() != 3)
5294 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5297 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5299 else if (!strcmp(Cmd_Argv(1), "corona"))
5301 if (Cmd_Argc() != 3)
5303 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5306 corona = atof(Cmd_Argv(2));
5308 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5310 if (Cmd_Argc() != 3)
5312 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5315 coronasizescale = atof(Cmd_Argv(2));
5317 else if (!strcmp(Cmd_Argv(1), "ambient"))
5319 if (Cmd_Argc() != 3)
5321 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5324 ambientscale = atof(Cmd_Argv(2));
5326 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5328 if (Cmd_Argc() != 3)
5330 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5333 diffusescale = atof(Cmd_Argv(2));
5335 else if (!strcmp(Cmd_Argv(1), "specular"))
5337 if (Cmd_Argc() != 3)
5339 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5342 specularscale = atof(Cmd_Argv(2));
5344 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5346 if (Cmd_Argc() != 3)
5348 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5351 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5353 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5355 if (Cmd_Argc() != 3)
5357 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5360 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5364 Con_Print("usage: r_editlights_edit [property] [value]\n");
5365 Con_Print("Selected light's properties:\n");
5366 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5367 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5368 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5369 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5370 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5371 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5372 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5373 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5374 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5375 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5376 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5377 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5378 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5379 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5382 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5383 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5386 void R_Shadow_EditLights_EditAll_f(void)
5392 if (!r_editlights.integer)
5394 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5398 // EditLights doesn't seem to have a "remove" command or something so:
5399 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5400 for (lightindex = 0;lightindex < range;lightindex++)
5402 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5405 R_Shadow_SelectLight(light);
5406 R_Shadow_EditLights_Edit_f();
5410 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5412 int lightnumber, lightcount;
5413 size_t lightindex, range;
5417 if (!r_editlights.integer)
5419 x = vid_conwidth.value - 240;
5421 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5424 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5425 for (lightindex = 0;lightindex < range;lightindex++)
5427 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5430 if (light == r_shadow_selectedlight)
5431 lightnumber = lightindex;
5434 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;
5435 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;
5437 if (r_shadow_selectedlight == NULL)
5439 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;
5440 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;
5441 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;
5442 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;
5443 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;
5444 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;
5445 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;
5446 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;
5447 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;
5448 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;
5449 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;
5450 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;
5451 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;
5452 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;
5453 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;
5456 void R_Shadow_EditLights_ToggleShadow_f(void)
5458 if (!r_editlights.integer)
5460 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5463 if (!r_shadow_selectedlight)
5465 Con_Print("No selected light.\n");
5468 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);
5471 void R_Shadow_EditLights_ToggleCorona_f(void)
5473 if (!r_editlights.integer)
5475 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5478 if (!r_shadow_selectedlight)
5480 Con_Print("No selected light.\n");
5483 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);
5486 void R_Shadow_EditLights_Remove_f(void)
5488 if (!r_editlights.integer)
5490 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5493 if (!r_shadow_selectedlight)
5495 Con_Print("No selected light.\n");
5498 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5499 r_shadow_selectedlight = NULL;
5502 void R_Shadow_EditLights_Help_f(void)
5505 "Documentation on r_editlights system:\n"
5507 "r_editlights : enable/disable editing mode\n"
5508 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5509 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5510 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5511 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5512 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5514 "r_editlights_help : this help\n"
5515 "r_editlights_clear : remove all lights\n"
5516 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5517 "r_editlights_save : save to .rtlights file\n"
5518 "r_editlights_spawn : create a light with default settings\n"
5519 "r_editlights_edit command : edit selected light - more documentation below\n"
5520 "r_editlights_remove : remove selected light\n"
5521 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5522 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5523 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5525 "origin x y z : set light location\n"
5526 "originx x: set x component of light location\n"
5527 "originy y: set y component of light location\n"
5528 "originz z: set z component of light location\n"
5529 "move x y z : adjust light location\n"
5530 "movex x: adjust x component of light location\n"
5531 "movey y: adjust y component of light location\n"
5532 "movez z: adjust z component of light location\n"
5533 "angles x y z : set light angles\n"
5534 "anglesx x: set x component of light angles\n"
5535 "anglesy y: set y component of light angles\n"
5536 "anglesz z: set z component of light angles\n"
5537 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5538 "radius radius : set radius (size) of light\n"
5539 "colorscale grey : multiply color of light (1 does nothing)\n"
5540 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5541 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5542 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5543 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5544 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5545 "shadows 1/0 : turn on/off shadows\n"
5546 "corona n : set corona intensity\n"
5547 "coronasize n : set corona size (0-1)\n"
5548 "ambient n : set ambient intensity (0-1)\n"
5549 "diffuse n : set diffuse intensity (0-1)\n"
5550 "specular n : set specular intensity (0-1)\n"
5551 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5552 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5553 "<nothing> : print light properties to console\n"
5557 void R_Shadow_EditLights_CopyInfo_f(void)
5559 if (!r_editlights.integer)
5561 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5564 if (!r_shadow_selectedlight)
5566 Con_Print("No selected light.\n");
5569 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5570 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5571 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5572 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5573 if (r_shadow_selectedlight->cubemapname)
5574 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5576 r_shadow_bufferlight.cubemapname[0] = 0;
5577 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5578 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5579 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5580 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5581 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5582 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5583 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5586 void R_Shadow_EditLights_PasteInfo_f(void)
5588 if (!r_editlights.integer)
5590 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5593 if (!r_shadow_selectedlight)
5595 Con_Print("No selected light.\n");
5598 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);
5601 void R_Shadow_EditLights_Init(void)
5603 Cvar_RegisterVariable(&r_editlights);
5604 Cvar_RegisterVariable(&r_editlights_cursordistance);
5605 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5606 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5607 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5608 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5609 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5610 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5611 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)");
5612 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5613 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5614 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5615 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)");
5616 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5617 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5618 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5619 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5620 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5621 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5622 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)");
5628 =============================================================================
5632 =============================================================================
5635 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5637 VectorClear(diffusecolor);
5638 VectorClear(diffusenormal);
5640 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5642 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5643 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5646 VectorSet(ambientcolor, 1, 1, 1);
5653 for (i = 0;i < r_refdef.scene.numlights;i++)
5655 light = r_refdef.scene.lights[i];
5656 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5657 f = 1 - VectorLength2(v);
5658 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5659 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);