3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmaprectangletexture;
248 rtexture_t *r_shadow_shadowmap2dtexture;
249 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 // lights are reloaded when this changes
255 char r_shadow_mapname[MAX_QPATH];
257 // used only for light filters (cubemaps)
258 rtexturepool_t *r_shadow_filters_texturepool;
260 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
261 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
262 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
263 cvar_t r_shadow_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"};
264 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
265 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
266 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
267 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
268 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
269 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
270 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
271 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
274 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
275 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
276 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
277 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
278 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
279 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
280 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
281 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
282 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
283 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
284 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
285 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
286 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
287 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
288 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
289 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
290 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
291 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
292 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
293 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
294 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
295 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
298 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
299 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
300 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
301 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
302 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
303 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
304 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
305 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
306 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
307 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
308 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
309 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
310 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
311 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
312 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
313 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
314 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
315 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
316 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
317 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
318 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
319 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
320 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
322 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
323 #define ATTENTABLESIZE 256
324 // 1D gradient, 2D circle and 3D sphere attenuation textures
325 #define ATTEN1DSIZE 32
326 #define ATTEN2DSIZE 64
327 #define ATTEN3DSIZE 32
329 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
330 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
331 static float r_shadow_attentable[ATTENTABLESIZE+1];
333 rtlight_t *r_shadow_compilingrtlight;
334 static memexpandablearray_t r_shadow_worldlightsarray;
335 dlight_t *r_shadow_selectedlight;
336 dlight_t r_shadow_bufferlight;
337 vec3_t r_editlights_cursorlocation;
339 extern int con_vislines;
341 typedef struct cubemapinfo_s
348 static int numcubemaps;
349 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 #define EDLIGHTSPRSIZE 8
362 skinframe_t *r_editlights_sprcursor;
363 skinframe_t *r_editlights_sprlight;
364 skinframe_t *r_editlights_sprnoshadowlight;
365 skinframe_t *r_editlights_sprcubemaplight;
366 skinframe_t *r_editlights_sprcubemapnoshadowlight;
367 skinframe_t *r_editlights_sprselection;
369 void R_Shadow_SetShadowMode(void)
371 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
372 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
373 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
374 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
375 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
376 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
377 r_shadow_shadowmaplod = -1;
378 r_shadow_shadowmapsize = 0;
379 r_shadow_shadowmapsampler = false;
380 r_shadow_shadowmappcf = 0;
381 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
382 switch(vid.renderpath)
384 case RENDERPATH_GL20:
385 if(r_shadow_shadowmapping.integer && vid.support.ext_framebuffer_object)
387 if(r_shadow_shadowmapfilterquality < 0)
389 if(strstr(gl_vendor, "NVIDIA"))
391 r_shadow_shadowmapsampler = vid.support.arb_shadow;
392 r_shadow_shadowmappcf = 1;
394 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
395 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "ATI"))
397 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmapsampler = vid.support.arb_shadow;
403 switch (r_shadow_shadowmapfilterquality)
406 r_shadow_shadowmapsampler = vid.support.arb_shadow;
409 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmappcf = 1;
413 r_shadow_shadowmappcf = 1;
416 r_shadow_shadowmappcf = 2;
420 switch (r_shadow_shadowmaptexturetype)
423 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
426 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
429 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
432 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
433 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
434 else if(vid.support.arb_texture_rectangle)
435 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
437 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
442 case RENDERPATH_GL13:
444 case RENDERPATH_GL11:
449 void R_Shadow_FreeShadowMaps(void)
453 R_Shadow_SetShadowMode();
455 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
460 if (r_shadow_fborectangle)
461 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
462 r_shadow_fborectangle = 0;
465 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
467 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
468 if (r_shadow_fbocubeside[i])
469 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
470 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
472 if (r_shadow_shadowmaprectangletexture)
473 R_FreeTexture(r_shadow_shadowmaprectangletexture);
474 r_shadow_shadowmaprectangletexture = NULL;
476 if (r_shadow_shadowmap2dtexture)
477 R_FreeTexture(r_shadow_shadowmap2dtexture);
478 r_shadow_shadowmap2dtexture = NULL;
480 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
481 if (r_shadow_shadowmapcubetexture[i])
482 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
483 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
485 if (r_shadow_shadowmapvsdcttexture)
486 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
487 r_shadow_shadowmapvsdcttexture = NULL;
492 void r_shadow_start(void)
494 // allocate vertex processing arrays
496 r_shadow_attenuationgradienttexture = NULL;
497 r_shadow_attenuation2dtexture = NULL;
498 r_shadow_attenuation3dtexture = NULL;
499 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
500 r_shadow_shadowmaprectangletexture = NULL;
501 r_shadow_shadowmap2dtexture = NULL;
502 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
503 r_shadow_shadowmapvsdcttexture = NULL;
504 r_shadow_shadowmapmaxsize = 0;
505 r_shadow_shadowmapsize = 0;
506 r_shadow_shadowmaplod = 0;
507 r_shadow_shadowmapfilterquality = -1;
508 r_shadow_shadowmaptexturetype = -1;
509 r_shadow_shadowmapdepthbits = 0;
510 r_shadow_shadowmapvsdct = false;
511 r_shadow_shadowmapsampler = false;
512 r_shadow_shadowmappcf = 0;
513 r_shadow_fborectangle = 0;
515 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
517 R_Shadow_FreeShadowMaps();
519 r_shadow_texturepool = NULL;
520 r_shadow_filters_texturepool = NULL;
521 R_Shadow_ValidateCvars();
522 R_Shadow_MakeTextures();
523 maxshadowtriangles = 0;
524 shadowelements = NULL;
525 maxshadowvertices = 0;
526 shadowvertex3f = NULL;
534 shadowmarklist = NULL;
539 shadowsideslist = NULL;
540 r_shadow_buffer_numleafpvsbytes = 0;
541 r_shadow_buffer_visitingleafpvs = NULL;
542 r_shadow_buffer_leafpvs = NULL;
543 r_shadow_buffer_leaflist = NULL;
544 r_shadow_buffer_numsurfacepvsbytes = 0;
545 r_shadow_buffer_surfacepvs = NULL;
546 r_shadow_buffer_surfacelist = NULL;
547 r_shadow_buffer_surfacesides = NULL;
548 r_shadow_buffer_numshadowtrispvsbytes = 0;
549 r_shadow_buffer_shadowtrispvs = NULL;
550 r_shadow_buffer_numlighttrispvsbytes = 0;
551 r_shadow_buffer_lighttrispvs = NULL;
554 void r_shadow_shutdown(void)
557 R_Shadow_UncompileWorldLights();
559 R_Shadow_FreeShadowMaps();
563 r_shadow_attenuationgradienttexture = NULL;
564 r_shadow_attenuation2dtexture = NULL;
565 r_shadow_attenuation3dtexture = NULL;
566 R_FreeTexturePool(&r_shadow_texturepool);
567 R_FreeTexturePool(&r_shadow_filters_texturepool);
568 maxshadowtriangles = 0;
570 Mem_Free(shadowelements);
571 shadowelements = NULL;
573 Mem_Free(shadowvertex3f);
574 shadowvertex3f = NULL;
577 Mem_Free(vertexupdate);
580 Mem_Free(vertexremap);
586 Mem_Free(shadowmark);
589 Mem_Free(shadowmarklist);
590 shadowmarklist = NULL;
595 Mem_Free(shadowsides);
598 Mem_Free(shadowsideslist);
599 shadowsideslist = NULL;
600 r_shadow_buffer_numleafpvsbytes = 0;
601 if (r_shadow_buffer_visitingleafpvs)
602 Mem_Free(r_shadow_buffer_visitingleafpvs);
603 r_shadow_buffer_visitingleafpvs = NULL;
604 if (r_shadow_buffer_leafpvs)
605 Mem_Free(r_shadow_buffer_leafpvs);
606 r_shadow_buffer_leafpvs = NULL;
607 if (r_shadow_buffer_leaflist)
608 Mem_Free(r_shadow_buffer_leaflist);
609 r_shadow_buffer_leaflist = NULL;
610 r_shadow_buffer_numsurfacepvsbytes = 0;
611 if (r_shadow_buffer_surfacepvs)
612 Mem_Free(r_shadow_buffer_surfacepvs);
613 r_shadow_buffer_surfacepvs = NULL;
614 if (r_shadow_buffer_surfacelist)
615 Mem_Free(r_shadow_buffer_surfacelist);
616 r_shadow_buffer_surfacelist = NULL;
617 if (r_shadow_buffer_surfacesides)
618 Mem_Free(r_shadow_buffer_surfacesides);
619 r_shadow_buffer_surfacesides = NULL;
620 r_shadow_buffer_numshadowtrispvsbytes = 0;
621 if (r_shadow_buffer_shadowtrispvs)
622 Mem_Free(r_shadow_buffer_shadowtrispvs);
623 r_shadow_buffer_numlighttrispvsbytes = 0;
624 if (r_shadow_buffer_lighttrispvs)
625 Mem_Free(r_shadow_buffer_lighttrispvs);
628 void r_shadow_newmap(void)
630 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
631 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
632 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
633 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
634 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
635 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
636 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
637 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
638 R_Shadow_EditLights_Reload_f();
641 void R_Shadow_Init(void)
643 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
644 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
645 Cvar_RegisterVariable(&r_shadow_dot3);
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 if (vid.support.arb_texture_env_dot3 && vid.support.arb_texture_cube_map && r_shadow_dot3.integer && vid.stencil)
1884 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1886 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1888 case RENDERPATH_GL11:
1889 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1895 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1896 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1897 r_shadow_drawbuffer = drawbuffer;
1898 r_shadow_readbuffer = readbuffer;
1900 r_shadow_cullface_front = r_refdef.view.cullface_front;
1901 r_shadow_cullface_back = r_refdef.view.cullface_back;
1904 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1906 rsurface.rtlight = rtlight;
1909 void R_Shadow_RenderMode_Reset(void)
1912 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1914 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1916 if (vid.support.ext_framebuffer_object)
1918 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1921 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1922 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1924 R_SetViewport(&r_refdef.view.viewport);
1925 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1926 R_Mesh_ColorPointer(NULL, 0, 0);
1927 R_Mesh_ResetTextureState();
1928 GL_DepthRange(0, 1);
1930 GL_DepthMask(false);
1931 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1932 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1933 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1934 qglStencilMask(~0);CHECKGLERROR
1935 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1936 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1937 r_refdef.view.cullface_front = r_shadow_cullface_front;
1938 r_refdef.view.cullface_back = r_shadow_cullface_back;
1939 GL_CullFace(r_refdef.view.cullface_back);
1940 GL_Color(1, 1, 1, 1);
1941 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1942 GL_BlendFunc(GL_ONE, GL_ZERO);
1943 R_SetupGenericShader(false);
1944 r_shadow_usingshadowmaprect = false;
1945 r_shadow_usingshadowmapcube = false;
1946 r_shadow_usingshadowmap2d = false;
1950 void R_Shadow_ClearStencil(void)
1953 GL_Clear(GL_STENCIL_BUFFER_BIT);
1954 r_refdef.stats.lights_clears++;
1957 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1959 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1960 if (r_shadow_rendermode == mode)
1963 R_Shadow_RenderMode_Reset();
1964 GL_ColorMask(0, 0, 0, 0);
1965 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1966 R_SetupDepthOrShadowShader();
1967 qglDepthFunc(GL_LESS);CHECKGLERROR
1968 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1969 r_shadow_rendermode = mode;
1974 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1975 GL_CullFace(GL_NONE);
1976 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1977 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1979 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1980 GL_CullFace(GL_NONE);
1981 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1982 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1984 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1985 GL_CullFace(GL_NONE);
1986 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1987 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1988 qglStencilMask(~0);CHECKGLERROR
1989 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1990 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1991 qglStencilMask(~0);CHECKGLERROR
1992 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1994 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1995 GL_CullFace(GL_NONE);
1996 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1997 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1998 qglStencilMask(~0);CHECKGLERROR
1999 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2000 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2001 qglStencilMask(~0);CHECKGLERROR
2002 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2007 static void R_Shadow_MakeVSDCT(void)
2009 // maps to a 2x3 texture rectangle with normalized coordinates
2014 // stores abs(dir.xy), offset.xy/2.5
2015 unsigned char data[4*6] =
2017 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2018 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2019 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2020 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2021 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2022 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2024 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2027 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2031 float nearclip, farclip, bias;
2032 r_viewport_t viewport;
2035 maxsize = r_shadow_shadowmapmaxsize;
2036 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2038 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2039 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2040 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2041 r_shadow_shadowmapside = side;
2042 r_shadow_shadowmapsize = size;
2043 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2045 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2046 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2047 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2048 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2050 // complex unrolled cube approach (more flexible)
2051 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2052 R_Shadow_MakeVSDCT();
2053 if (!r_shadow_shadowmap2dtexture)
2056 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2057 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2058 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2059 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2060 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2061 // render depth into the fbo, do not render color at all
2062 qglDrawBuffer(GL_NONE);CHECKGLERROR
2063 qglReadBuffer(GL_NONE);CHECKGLERROR
2064 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2065 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2067 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2068 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2073 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2074 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2075 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2076 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2078 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2080 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2081 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2082 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2083 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2085 // complex unrolled cube approach (more flexible)
2086 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2087 R_Shadow_MakeVSDCT();
2088 if (!r_shadow_shadowmaprectangletexture)
2091 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2092 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2093 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2094 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2095 // render depth into the fbo, do not render color at all
2096 qglDrawBuffer(GL_NONE);CHECKGLERROR
2097 qglReadBuffer(GL_NONE);CHECKGLERROR
2098 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2099 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2101 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2102 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2107 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2108 r_shadow_shadowmap_texturescale[0] = 1.0f;
2109 r_shadow_shadowmap_texturescale[1] = 1.0f;
2110 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2112 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2114 r_shadow_shadowmap_parameters[0] = 1.0f;
2115 r_shadow_shadowmap_parameters[1] = 1.0f;
2116 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2117 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2119 // simple cube approach
2120 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2123 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2124 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2125 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2126 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
2127 // render depth into the fbo, do not render color at all
2128 qglDrawBuffer(GL_NONE);CHECKGLERROR
2129 qglReadBuffer(GL_NONE);CHECKGLERROR
2130 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2131 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2133 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2134 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2139 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2140 r_shadow_shadowmap_texturescale[0] = 0.0f;
2141 r_shadow_shadowmap_texturescale[1] = 0.0f;
2142 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2145 R_Shadow_RenderMode_Reset();
2148 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2149 R_SetupDepthOrShadowShader();
2153 R_SetupShowDepthShader();
2154 qglClearColor(1,1,1,1);CHECKGLERROR
2157 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2164 R_SetViewport(&viewport);
2165 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2166 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2168 int flipped = (side&1)^(side>>2);
2169 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2170 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2171 GL_CullFace(r_refdef.view.cullface_back);
2173 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2175 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
2178 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2182 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2186 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2187 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2188 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2189 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2192 R_Shadow_RenderMode_Reset();
2193 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2196 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2200 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2201 // only draw light where this geometry was already rendered AND the
2202 // stencil is 128 (values other than this mean shadow)
2203 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2205 r_shadow_rendermode = r_shadow_lightingrendermode;
2206 // do global setup needed for the chosen lighting mode
2207 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2209 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2210 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2214 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2216 r_shadow_usingshadowmap2d = true;
2217 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2220 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2222 r_shadow_usingshadowmaprect = true;
2223 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2226 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2228 r_shadow_usingshadowmapcube = true;
2229 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2233 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2235 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2240 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2241 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2245 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2248 R_Shadow_RenderMode_Reset();
2249 GL_BlendFunc(GL_ONE, GL_ONE);
2250 GL_DepthRange(0, 1);
2251 GL_DepthTest(r_showshadowvolumes.integer < 2);
2252 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2253 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2254 GL_CullFace(GL_NONE);
2255 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2258 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2261 R_Shadow_RenderMode_Reset();
2262 GL_BlendFunc(GL_ONE, GL_ONE);
2263 GL_DepthRange(0, 1);
2264 GL_DepthTest(r_showlighting.integer < 2);
2265 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2268 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2272 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2273 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2275 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2278 void R_Shadow_RenderMode_End(void)
2281 R_Shadow_RenderMode_Reset();
2282 R_Shadow_RenderMode_ActiveLight(NULL);
2284 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2285 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2288 int bboxedges[12][2] =
2307 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2309 int i, ix1, iy1, ix2, iy2;
2310 float x1, y1, x2, y2;
2312 float vertex[20][3];
2321 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2322 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2323 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2324 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2326 if (!r_shadow_scissor.integer)
2329 // if view is inside the light box, just say yes it's visible
2330 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2333 x1 = y1 = x2 = y2 = 0;
2335 // transform all corners that are infront of the nearclip plane
2336 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2337 plane4f[3] = r_refdef.view.frustum[4].dist;
2339 for (i = 0;i < 8;i++)
2341 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2342 dist[i] = DotProduct4(corner[i], plane4f);
2343 sign[i] = dist[i] > 0;
2346 VectorCopy(corner[i], vertex[numvertices]);
2350 // if some points are behind the nearclip, add clipped edge points to make
2351 // sure that the scissor boundary is complete
2352 if (numvertices > 0 && numvertices < 8)
2354 // add clipped edge points
2355 for (i = 0;i < 12;i++)
2357 j = bboxedges[i][0];
2358 k = bboxedges[i][1];
2359 if (sign[j] != sign[k])
2361 f = dist[j] / (dist[j] - dist[k]);
2362 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2368 // if we have no points to check, the light is behind the view plane
2372 // if we have some points to transform, check what screen area is covered
2373 x1 = y1 = x2 = y2 = 0;
2375 //Con_Printf("%i vertices to transform...\n", numvertices);
2376 for (i = 0;i < numvertices;i++)
2378 VectorCopy(vertex[i], v);
2379 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2380 //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]);
2383 if (x1 > v2[0]) x1 = v2[0];
2384 if (x2 < v2[0]) x2 = v2[0];
2385 if (y1 > v2[1]) y1 = v2[1];
2386 if (y2 < v2[1]) y2 = v2[1];
2395 // now convert the scissor rectangle to integer screen coordinates
2396 ix1 = (int)(x1 - 1.0f);
2397 iy1 = vid.height - (int)(y2 - 1.0f);
2398 ix2 = (int)(x2 + 1.0f);
2399 iy2 = vid.height - (int)(y1 + 1.0f);
2400 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2402 // clamp it to the screen
2403 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2404 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2405 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2406 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2408 // if it is inside out, it's not visible
2409 if (ix2 <= ix1 || iy2 <= iy1)
2412 // the light area is visible, set up the scissor rectangle
2413 r_shadow_lightscissor[0] = ix1;
2414 r_shadow_lightscissor[1] = iy1;
2415 r_shadow_lightscissor[2] = ix2 - ix1;
2416 r_shadow_lightscissor[3] = iy2 - iy1;
2418 r_refdef.stats.lights_scissored++;
2422 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2424 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2425 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2426 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2427 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2428 if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2430 if (VectorLength2(diffusecolor) > 0)
2432 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2434 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2435 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2436 if ((dot = DotProduct(n, v)) < 0)
2438 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2439 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2442 VectorCopy(ambientcolor, color4f);
2443 if (r_refdef.fogenabled)
2446 f = RSurf_FogVertex(vertex3f);
2447 VectorScale(color4f, f, color4f);
2454 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2456 VectorCopy(ambientcolor, color4f);
2457 if (r_refdef.fogenabled)
2460 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2461 f = RSurf_FogVertex(vertex3f);
2462 VectorScale(color4f, f, color4f);
2468 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2470 if (VectorLength2(diffusecolor) > 0)
2472 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2474 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2475 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2477 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2478 if ((dot = DotProduct(n, v)) < 0)
2480 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2481 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2482 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2483 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2487 color4f[0] = ambientcolor[0] * distintensity;
2488 color4f[1] = ambientcolor[1] * distintensity;
2489 color4f[2] = ambientcolor[2] * distintensity;
2491 if (r_refdef.fogenabled)
2494 f = RSurf_FogVertex(vertex3f);
2495 VectorScale(color4f, f, color4f);
2499 VectorClear(color4f);
2505 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2507 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2508 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2510 color4f[0] = ambientcolor[0] * distintensity;
2511 color4f[1] = ambientcolor[1] * distintensity;
2512 color4f[2] = ambientcolor[2] * distintensity;
2513 if (r_refdef.fogenabled)
2516 f = RSurf_FogVertex(vertex3f);
2517 VectorScale(color4f, f, color4f);
2521 VectorClear(color4f);
2528 if (VectorLength2(diffusecolor) > 0)
2530 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2532 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2533 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2535 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2536 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2537 if ((dot = DotProduct(n, v)) < 0)
2539 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2540 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2541 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2542 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2546 color4f[0] = ambientcolor[0] * distintensity;
2547 color4f[1] = ambientcolor[1] * distintensity;
2548 color4f[2] = ambientcolor[2] * distintensity;
2550 if (r_refdef.fogenabled)
2553 f = RSurf_FogVertex(vertex3f);
2554 VectorScale(color4f, f, color4f);
2558 VectorClear(color4f);
2564 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2566 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2567 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2569 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2570 color4f[0] = ambientcolor[0] * distintensity;
2571 color4f[1] = ambientcolor[1] * distintensity;
2572 color4f[2] = ambientcolor[2] * distintensity;
2573 if (r_refdef.fogenabled)
2576 f = RSurf_FogVertex(vertex3f);
2577 VectorScale(color4f, f, color4f);
2581 VectorClear(color4f);
2588 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2590 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2593 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2594 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2595 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2596 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2597 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2599 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2601 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2602 // the cubemap normalizes this for us
2603 out3f[0] = DotProduct(svector3f, lightdir);
2604 out3f[1] = DotProduct(tvector3f, lightdir);
2605 out3f[2] = DotProduct(normal3f, lightdir);
2609 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2612 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2613 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2614 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2615 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2616 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2617 float lightdir[3], eyedir[3], halfdir[3];
2618 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2620 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2621 VectorNormalize(lightdir);
2622 VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir);
2623 VectorNormalize(eyedir);
2624 VectorAdd(lightdir, eyedir, halfdir);
2625 // the cubemap normalizes this for us
2626 out3f[0] = DotProduct(svector3f, halfdir);
2627 out3f[1] = DotProduct(tvector3f, halfdir);
2628 out3f[2] = DotProduct(normal3f, halfdir);
2632 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)
2634 // used to display how many times a surface is lit for level design purposes
2635 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2638 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)
2640 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2641 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2642 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2643 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2645 R_Mesh_ColorPointer(NULL, 0, 0);
2646 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2647 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2648 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2649 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2650 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2651 if (rsurface.texture->backgroundcurrentskinframe)
2653 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2654 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2655 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2656 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2658 //R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
2659 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2660 if(rsurface.texture->colormapping)
2662 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2663 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2665 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2666 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2667 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2668 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2669 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2670 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2672 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2674 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2675 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2677 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2681 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
2683 // shared final code for all the dot3 layers
2685 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2686 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2688 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2689 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2693 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, float colorscale)
2696 // colorscale accounts for how much we multiply the brightness
2699 // mult is how many times the final pass of the lighting will be
2700 // performed to get more brightness than otherwise possible.
2702 // Limit mult to 64 for sanity sake.
2704 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4 && vid.texunits >= 4)
2706 // 3 3D combine path (Geforce3, Radeon 8500)
2707 memset(&m, 0, sizeof(m));
2708 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2709 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2710 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2711 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2712 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2713 m.tex[1] = R_GetTexture(basetexture);
2714 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2715 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2716 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2717 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2718 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2719 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2720 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2721 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2722 m.texmatrix[2] = rsurface.entitytolight;
2723 GL_BlendFunc(GL_ONE, GL_ONE);
2725 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2 && vid.texunits >= 2)
2727 // 2 3D combine path (Geforce3, original Radeon)
2728 memset(&m, 0, sizeof(m));
2729 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2730 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2731 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2732 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2733 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2734 m.tex[1] = R_GetTexture(basetexture);
2735 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2736 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2737 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2738 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2739 GL_BlendFunc(GL_ONE, GL_ONE);
2741 else if (r_textureunits.integer >= 4 && vid.texunits >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2743 // 4 2D combine path (Geforce3, Radeon 8500)
2744 memset(&m, 0, sizeof(m));
2745 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2746 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2747 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2748 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2749 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2750 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2751 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2752 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2753 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2754 m.texmatrix[1] = rsurface.entitytoattenuationz;
2755 m.tex[2] = R_GetTexture(basetexture);
2756 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2757 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2758 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2759 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2760 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2762 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2763 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2764 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2765 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2766 m.texmatrix[3] = rsurface.entitytolight;
2768 GL_BlendFunc(GL_ONE, GL_ONE);
2770 else if (r_textureunits.integer >= 3 && vid.texunits >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2772 // 3 2D combine path (Geforce3, original Radeon)
2773 memset(&m, 0, sizeof(m));
2774 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2775 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2776 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2777 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2778 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2779 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2780 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2781 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2782 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2783 m.texmatrix[1] = rsurface.entitytoattenuationz;
2784 m.tex[2] = R_GetTexture(basetexture);
2785 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2786 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2787 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2788 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2789 GL_BlendFunc(GL_ONE, GL_ONE);
2793 // 2/2/2 2D combine path (any dot3 card)
2794 memset(&m, 0, sizeof(m));
2795 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2796 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2797 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2798 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2799 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2800 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2801 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2802 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2803 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2804 m.texmatrix[1] = rsurface.entitytoattenuationz;
2805 R_Mesh_TextureState(&m);
2806 GL_ColorMask(0,0,0,1);
2807 GL_BlendFunc(GL_ONE, GL_ZERO);
2808 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2811 memset(&m, 0, sizeof(m));
2812 m.tex[0] = R_GetTexture(basetexture);
2813 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2814 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2815 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2816 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2817 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2819 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2820 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2821 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2822 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2823 m.texmatrix[1] = rsurface.entitytolight;
2825 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2827 // this final code is shared
2828 R_Mesh_TextureState(&m);
2829 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2832 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
2835 // colorscale accounts for how much we multiply the brightness
2838 // mult is how many times the final pass of the lighting will be
2839 // performed to get more brightness than otherwise possible.
2841 // Limit mult to 64 for sanity sake.
2843 // generate normalization cubemap texcoords
2844 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2845 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4 && vid.texunits >= 4)
2847 // 3/2 3D combine path (Geforce3, Radeon 8500)
2848 memset(&m, 0, sizeof(m));
2849 m.tex[0] = R_GetTexture(normalmaptexture);
2850 m.texcombinergb[0] = GL_REPLACE;
2851 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2852 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2853 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2854 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2855 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2856 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2857 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2858 m.pointer_texcoord_bufferobject[1] = 0;
2859 m.pointer_texcoord_bufferoffset[1] = 0;
2860 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2861 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2862 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2863 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2864 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2865 R_Mesh_TextureState(&m);
2866 GL_ColorMask(0,0,0,1);
2867 GL_BlendFunc(GL_ONE, GL_ZERO);
2868 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2871 memset(&m, 0, sizeof(m));
2872 m.tex[0] = R_GetTexture(basetexture);
2873 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2874 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2875 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2876 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2877 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2879 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2880 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2881 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2882 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2883 m.texmatrix[1] = rsurface.entitytolight;
2885 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2887 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && vid.texunits >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2889 // 1/2/2 3D combine path (original Radeon)
2890 memset(&m, 0, sizeof(m));
2891 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2892 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2893 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2894 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2895 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2896 R_Mesh_TextureState(&m);
2897 GL_ColorMask(0,0,0,1);
2898 GL_BlendFunc(GL_ONE, GL_ZERO);
2899 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2902 memset(&m, 0, sizeof(m));
2903 m.tex[0] = R_GetTexture(normalmaptexture);
2904 m.texcombinergb[0] = GL_REPLACE;
2905 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2906 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2907 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2908 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2909 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2910 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2911 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2912 m.pointer_texcoord_bufferobject[1] = 0;
2913 m.pointer_texcoord_bufferoffset[1] = 0;
2914 R_Mesh_TextureState(&m);
2915 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2916 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2919 memset(&m, 0, sizeof(m));
2920 m.tex[0] = R_GetTexture(basetexture);
2921 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2922 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2923 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2924 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2925 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2927 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2928 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2929 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2930 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2931 m.texmatrix[1] = rsurface.entitytolight;
2933 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2935 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && vid.texunits >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2937 // 2/2 3D combine path (original Radeon)
2938 memset(&m, 0, sizeof(m));
2939 m.tex[0] = R_GetTexture(normalmaptexture);
2940 m.texcombinergb[0] = GL_REPLACE;
2941 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2942 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2943 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2944 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2945 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2946 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2947 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2948 m.pointer_texcoord_bufferobject[1] = 0;
2949 m.pointer_texcoord_bufferoffset[1] = 0;
2950 R_Mesh_TextureState(&m);
2951 GL_ColorMask(0,0,0,1);
2952 GL_BlendFunc(GL_ONE, GL_ZERO);
2953 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2956 memset(&m, 0, sizeof(m));
2957 m.tex[0] = R_GetTexture(basetexture);
2958 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2959 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2960 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2961 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2962 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2963 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2964 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2965 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2966 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2967 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2969 else if (r_textureunits.integer >= 4 && vid.texunits >= 4)
2971 // 4/2 2D combine path (Geforce3, Radeon 8500)
2972 memset(&m, 0, sizeof(m));
2973 m.tex[0] = R_GetTexture(normalmaptexture);
2974 m.texcombinergb[0] = GL_REPLACE;
2975 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2976 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2977 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2978 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2979 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2980 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2981 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2982 m.pointer_texcoord_bufferobject[1] = 0;
2983 m.pointer_texcoord_bufferoffset[1] = 0;
2984 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2985 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2986 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2987 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2988 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2989 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2990 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2991 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2992 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2993 m.texmatrix[3] = rsurface.entitytoattenuationz;
2994 R_Mesh_TextureState(&m);
2995 GL_ColorMask(0,0,0,1);
2996 GL_BlendFunc(GL_ONE, GL_ZERO);
2997 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3000 memset(&m, 0, sizeof(m));
3001 m.tex[0] = R_GetTexture(basetexture);
3002 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3003 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3004 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3005 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3006 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3008 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3009 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3010 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3011 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3012 m.texmatrix[1] = rsurface.entitytolight;
3014 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3018 // 2/2/2 2D combine path (any dot3 card)
3019 memset(&m, 0, sizeof(m));
3020 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3021 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3022 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3023 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3024 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3025 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3026 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3027 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3028 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3029 m.texmatrix[1] = rsurface.entitytoattenuationz;
3030 R_Mesh_TextureState(&m);
3031 GL_ColorMask(0,0,0,1);
3032 GL_BlendFunc(GL_ONE, GL_ZERO);
3033 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3036 memset(&m, 0, sizeof(m));
3037 m.tex[0] = R_GetTexture(normalmaptexture);
3038 m.texcombinergb[0] = GL_REPLACE;
3039 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3040 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3041 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3042 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3043 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3044 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3045 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3046 m.pointer_texcoord_bufferobject[1] = 0;
3047 m.pointer_texcoord_bufferoffset[1] = 0;
3048 R_Mesh_TextureState(&m);
3049 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3050 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3053 memset(&m, 0, sizeof(m));
3054 m.tex[0] = R_GetTexture(basetexture);
3055 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3056 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3057 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3058 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3059 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3061 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3062 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3063 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3064 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3065 m.texmatrix[1] = rsurface.entitytolight;
3067 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3069 // this final code is shared
3070 R_Mesh_TextureState(&m);
3071 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
3074 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
3076 float glossexponent;
3078 // FIXME: detect blendsquare!
3079 //if (!gl_support_blendsquare)
3082 // generate normalization cubemap texcoords
3083 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
3084 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && vid.texunits >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
3086 // 2/0/0/1/2 3D combine blendsquare path
3087 memset(&m, 0, sizeof(m));
3088 m.tex[0] = R_GetTexture(normalmaptexture);
3089 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3090 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3091 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3092 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3093 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3094 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3095 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3096 m.pointer_texcoord_bufferobject[1] = 0;
3097 m.pointer_texcoord_bufferoffset[1] = 0;
3098 R_Mesh_TextureState(&m);
3099 GL_ColorMask(0,0,0,1);
3100 // this squares the result
3101 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3102 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3104 // second and third pass
3105 R_Mesh_ResetTextureState();
3106 // square alpha in framebuffer a few times to make it shiny
3107 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3108 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3109 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3112 memset(&m, 0, sizeof(m));
3113 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3114 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3115 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3116 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3117 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3118 R_Mesh_TextureState(&m);
3119 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3120 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3123 memset(&m, 0, sizeof(m));
3124 m.tex[0] = R_GetTexture(glosstexture);
3125 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3126 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3127 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3128 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3129 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3131 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3132 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3133 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3134 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3135 m.texmatrix[1] = rsurface.entitytolight;
3137 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3139 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && vid.texunits >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3141 // 2/0/0/2 3D combine blendsquare path
3142 memset(&m, 0, sizeof(m));
3143 m.tex[0] = R_GetTexture(normalmaptexture);
3144 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3145 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3146 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3147 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3148 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3149 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3150 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3151 m.pointer_texcoord_bufferobject[1] = 0;
3152 m.pointer_texcoord_bufferoffset[1] = 0;
3153 R_Mesh_TextureState(&m);
3154 GL_ColorMask(0,0,0,1);
3155 // this squares the result
3156 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3157 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3159 // second and third pass
3160 R_Mesh_ResetTextureState();
3161 // square alpha in framebuffer a few times to make it shiny
3162 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3163 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3164 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3167 memset(&m, 0, sizeof(m));
3168 m.tex[0] = R_GetTexture(glosstexture);
3169 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3170 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3171 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3172 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3173 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3174 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3175 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3176 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3177 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3178 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3182 // 2/0/0/2/2 2D combine blendsquare path
3183 memset(&m, 0, sizeof(m));
3184 m.tex[0] = R_GetTexture(normalmaptexture);
3185 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3186 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3187 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3188 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3189 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3190 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3191 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3192 m.pointer_texcoord_bufferobject[1] = 0;
3193 m.pointer_texcoord_bufferoffset[1] = 0;
3194 R_Mesh_TextureState(&m);
3195 GL_ColorMask(0,0,0,1);
3196 // this squares the result
3197 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3198 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3200 // second and third pass
3201 R_Mesh_ResetTextureState();
3202 // square alpha in framebuffer a few times to make it shiny
3203 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3204 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3205 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3208 memset(&m, 0, sizeof(m));
3209 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3210 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3211 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3212 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3213 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3214 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3215 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3216 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3217 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3218 m.texmatrix[1] = rsurface.entitytoattenuationz;
3219 R_Mesh_TextureState(&m);
3220 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3221 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3224 memset(&m, 0, sizeof(m));
3225 m.tex[0] = R_GetTexture(glosstexture);
3226 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3227 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3228 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3229 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3230 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3232 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3233 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3234 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3235 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3236 m.texmatrix[1] = rsurface.entitytolight;
3238 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3240 // this final code is shared
3241 R_Mesh_TextureState(&m);
3242 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
3245 static void R_Shadow_RenderLighting_Light_Dot3(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
3247 // ARB path (any Geforce, any Radeon)
3248 qboolean doambient = ambientscale > 0;
3249 qboolean dodiffuse = diffusescale > 0;
3250 qboolean dospecular = specularscale > 0;
3251 if (!doambient && !dodiffuse && !dospecular)
3253 R_Mesh_ColorPointer(NULL, 0, 0);
3255 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3257 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3261 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3263 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3268 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3270 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3273 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3276 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3283 int newnumtriangles;
3287 int maxtriangles = 4096;
3288 int newelements[4096*3];
3289 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3290 for (renders = 0;renders < 64;renders++)
3295 newnumtriangles = 0;
3297 // due to low fillrate on the cards this vertex lighting path is
3298 // designed for, we manually cull all triangles that do not
3299 // contain a lit vertex
3300 // this builds batches of triangles from multiple surfaces and
3301 // renders them at once
3302 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3304 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3306 if (newnumtriangles)
3308 newfirstvertex = min(newfirstvertex, e[0]);
3309 newlastvertex = max(newlastvertex, e[0]);
3313 newfirstvertex = e[0];
3314 newlastvertex = e[0];
3316 newfirstvertex = min(newfirstvertex, e[1]);
3317 newlastvertex = max(newlastvertex, e[1]);
3318 newfirstvertex = min(newfirstvertex, e[2]);
3319 newlastvertex = max(newlastvertex, e[2]);
3325 if (newnumtriangles >= maxtriangles)
3327 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3328 newnumtriangles = 0;
3334 if (newnumtriangles >= 1)
3336 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3339 // if we couldn't find any lit triangles, exit early
3342 // now reduce the intensity for the next overbright pass
3343 // we have to clamp to 0 here incase the drivers have improper
3344 // handling of negative colors
3345 // (some old drivers even have improper handling of >1 color)
3347 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3349 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3351 c[0] = max(0, c[0] - 1);
3352 c[1] = max(0, c[1] - 1);
3353 c[2] = max(0, c[2] - 1);
3365 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)
3367 // OpenGL 1.1 path (anything)
3368 float ambientcolorbase[3], diffusecolorbase[3];
3369 float ambientcolorpants[3], diffusecolorpants[3];
3370 float ambientcolorshirt[3], diffusecolorshirt[3];
3372 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3373 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3374 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3375 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3376 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3377 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3378 memset(&m, 0, sizeof(m));
3379 m.tex[0] = R_GetTexture(basetexture);
3380 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3381 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3382 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3383 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3384 if (r_textureunits.integer >= 2 && vid.texunits >= 2)
3387 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3388 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3389 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3390 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3391 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3392 if (r_textureunits.integer >= 3 && vid.texunits >= 3)
3394 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3395 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3396 m.texmatrix[2] = rsurface.entitytoattenuationz;
3397 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3398 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3399 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3402 R_Mesh_TextureState(&m);
3403 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3404 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3407 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3408 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3412 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3413 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3417 extern cvar_t gl_lightmaps;
3418 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)
3420 float ambientscale, diffusescale, specularscale;
3422 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3424 // calculate colors to render this texture with
3425 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3426 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3427 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3428 ambientscale = rsurface.rtlight->ambientscale;
3429 diffusescale = rsurface.rtlight->diffusescale;
3430 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3431 if (!r_shadow_usenormalmap.integer)
3433 ambientscale += 1.0f * diffusescale;
3437 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3439 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
3442 VectorNegate(lightcolorbase, lightcolorbase);
3443 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3445 RSurf_SetupDepthAndCulling();
3446 nmap = rsurface.texture->currentskinframe->nmap;
3447 if (gl_lightmaps.integer)
3448 nmap = r_texture_blanknormalmap;
3449 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3451 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3452 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3455 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3456 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3457 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3460 VectorClear(lightcolorpants);
3463 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3464 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3465 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3468 VectorClear(lightcolorshirt);
3469 switch (r_shadow_rendermode)
3471 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3472 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3473 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);
3475 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3476 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);
3478 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3479 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
3481 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3482 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);
3485 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3491 switch (r_shadow_rendermode)
3493 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3494 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3495 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);
3497 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3498 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);
3500 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3501 R_Shadow_RenderLighting_Light_Dot3(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
3503 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3504 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);
3507 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3512 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3515 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)
3517 matrix4x4_t tempmatrix = *matrix;
3518 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3520 // if this light has been compiled before, free the associated data
3521 R_RTLight_Uncompile(rtlight);
3523 // clear it completely to avoid any lingering data
3524 memset(rtlight, 0, sizeof(*rtlight));
3526 // copy the properties
3527 rtlight->matrix_lighttoworld = tempmatrix;
3528 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3529 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3530 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3531 VectorCopy(color, rtlight->color);
3532 rtlight->cubemapname[0] = 0;
3533 if (cubemapname && cubemapname[0])
3534 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3535 rtlight->shadow = shadow;
3536 rtlight->corona = corona;
3537 rtlight->style = style;
3538 rtlight->isstatic = isstatic;
3539 rtlight->coronasizescale = coronasizescale;
3540 rtlight->ambientscale = ambientscale;
3541 rtlight->diffusescale = diffusescale;
3542 rtlight->specularscale = specularscale;
3543 rtlight->flags = flags;
3545 // compute derived data
3546 //rtlight->cullradius = rtlight->radius;
3547 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3548 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3549 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3550 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3551 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3552 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3553 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3556 // compiles rtlight geometry
3557 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3558 void R_RTLight_Compile(rtlight_t *rtlight)
3561 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3562 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3563 entity_render_t *ent = r_refdef.scene.worldentity;
3564 dp_model_t *model = r_refdef.scene.worldmodel;
3565 unsigned char *data;
3568 // compile the light
3569 rtlight->compiled = true;
3570 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3571 rtlight->static_numleafs = 0;
3572 rtlight->static_numleafpvsbytes = 0;
3573 rtlight->static_leaflist = NULL;
3574 rtlight->static_leafpvs = NULL;
3575 rtlight->static_numsurfaces = 0;
3576 rtlight->static_surfacelist = NULL;
3577 rtlight->static_shadowmap_receivers = 0x3F;
3578 rtlight->static_shadowmap_casters = 0x3F;
3579 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3580 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3581 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3582 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3583 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3584 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3586 if (model && model->GetLightInfo)
3588 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3589 r_shadow_compilingrtlight = rtlight;
3590 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);
3591 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);
3592 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3593 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3594 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3595 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3596 rtlight->static_numsurfaces = numsurfaces;
3597 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3598 rtlight->static_numleafs = numleafs;
3599 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3600 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3601 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3602 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3603 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3604 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3605 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3606 if (rtlight->static_numsurfaces)
3607 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3608 if (rtlight->static_numleafs)
3609 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3610 if (rtlight->static_numleafpvsbytes)
3611 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3612 if (rtlight->static_numshadowtrispvsbytes)
3613 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3614 if (rtlight->static_numlighttrispvsbytes)
3615 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3616 switch (rtlight->shadowmode)
3618 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3619 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3620 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3621 if (model->CompileShadowMap && rtlight->shadow)
3622 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3625 if (model->CompileShadowVolume && rtlight->shadow)
3626 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3629 // now we're done compiling the rtlight
3630 r_shadow_compilingrtlight = NULL;
3634 // use smallest available cullradius - box radius or light radius
3635 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3636 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3638 shadowzpasstris = 0;
3639 if (rtlight->static_meshchain_shadow_zpass)
3640 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3641 shadowzpasstris += mesh->numtriangles;
3643 shadowzfailtris = 0;
3644 if (rtlight->static_meshchain_shadow_zfail)
3645 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3646 shadowzfailtris += mesh->numtriangles;
3649 if (rtlight->static_numlighttrispvsbytes)
3650 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3651 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3655 if (rtlight->static_numlighttrispvsbytes)
3656 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3657 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3660 if (developer.integer >= 10)
3661 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);
3664 void R_RTLight_Uncompile(rtlight_t *rtlight)
3666 if (rtlight->compiled)
3668 if (rtlight->static_meshchain_shadow_zpass)
3669 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3670 rtlight->static_meshchain_shadow_zpass = NULL;
3671 if (rtlight->static_meshchain_shadow_zfail)
3672 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3673 rtlight->static_meshchain_shadow_zfail = NULL;
3674 if (rtlight->static_meshchain_shadow_shadowmap)
3675 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3676 rtlight->static_meshchain_shadow_shadowmap = NULL;
3677 // these allocations are grouped
3678 if (rtlight->static_surfacelist)
3679 Mem_Free(rtlight->static_surfacelist);
3680 rtlight->static_numleafs = 0;
3681 rtlight->static_numleafpvsbytes = 0;
3682 rtlight->static_leaflist = NULL;
3683 rtlight->static_leafpvs = NULL;
3684 rtlight->static_numsurfaces = 0;
3685 rtlight->static_surfacelist = NULL;
3686 rtlight->static_numshadowtrispvsbytes = 0;
3687 rtlight->static_shadowtrispvs = NULL;
3688 rtlight->static_numlighttrispvsbytes = 0;
3689 rtlight->static_lighttrispvs = NULL;
3690 rtlight->compiled = false;
3694 void R_Shadow_UncompileWorldLights(void)
3698 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3699 for (lightindex = 0;lightindex < range;lightindex++)
3701 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3704 R_RTLight_Uncompile(&light->rtlight);
3708 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3712 // reset the count of frustum planes
3713 // see rsurface.rtlight_frustumplanes definition for how much this array
3715 rsurface.rtlight_numfrustumplanes = 0;
3717 // haven't implemented a culling path for ortho rendering
3718 if (!r_refdef.view.useperspective)
3720 // check if the light is on screen and copy the 4 planes if it is
3721 for (i = 0;i < 4;i++)
3722 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3725 for (i = 0;i < 4;i++)
3726 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3731 // generate a deformed frustum that includes the light origin, this is
3732 // used to cull shadow casting surfaces that can not possibly cast a
3733 // shadow onto the visible light-receiving surfaces, which can be a
3736 // if the light origin is onscreen the result will be 4 planes exactly
3737 // if the light origin is offscreen on only one axis the result will
3738 // be exactly 5 planes (split-side case)
3739 // if the light origin is offscreen on two axes the result will be
3740 // exactly 4 planes (stretched corner case)
3741 for (i = 0;i < 4;i++)
3743 // quickly reject standard frustum planes that put the light
3744 // origin outside the frustum
3745 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3748 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3750 // if all the standard frustum planes were accepted, the light is onscreen
3751 // otherwise we need to generate some more planes below...
3752 if (rsurface.rtlight_numfrustumplanes < 4)
3754 // at least one of the stock frustum planes failed, so we need to
3755 // create one or two custom planes to enclose the light origin
3756 for (i = 0;i < 4;i++)
3758 // create a plane using the view origin and light origin, and a
3759 // single point from the frustum corner set
3760 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3761 VectorNormalize(plane.normal);
3762 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3763 // see if this plane is backwards and flip it if so
3764 for (j = 0;j < 4;j++)
3765 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3769 VectorNegate(plane.normal, plane.normal);
3771 // flipped plane, test again to see if it is now valid
3772 for (j = 0;j < 4;j++)
3773 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3775 // if the plane is still not valid, then it is dividing the
3776 // frustum and has to be rejected
3780 // we have created a valid plane, compute extra info
3781 PlaneClassify(&plane);
3783 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3785 // if we've found 5 frustum planes then we have constructed a
3786 // proper split-side case and do not need to keep searching for
3787 // planes to enclose the light origin
3788 if (rsurface.rtlight_numfrustumplanes == 5)
3796 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3798 plane = rsurface.rtlight_frustumplanes[i];
3799 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));
3804 // now add the light-space box planes if the light box is rotated, as any
3805 // caster outside the oriented light box is irrelevant (even if it passed
3806 // the worldspace light box, which is axial)
3807 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3809 for (i = 0;i < 6;i++)
3813 v[i >> 1] = (i & 1) ? -1 : 1;
3814 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3815 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3816 plane.dist = VectorNormalizeLength(plane.normal);
3817 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3818 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3824 // add the world-space reduced box planes
3825 for (i = 0;i < 6;i++)
3827 VectorClear(plane.normal);
3828 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3829 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3830 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3839 // reduce all plane distances to tightly fit the rtlight cull box, which
3841 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3842 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3843 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3844 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3845 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3846 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3847 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3848 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3849 oldnum = rsurface.rtlight_numfrustumplanes;
3850 rsurface.rtlight_numfrustumplanes = 0;
3851 for (j = 0;j < oldnum;j++)
3853 // find the nearest point on the box to this plane
3854 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3855 for (i = 1;i < 8;i++)
3857 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3858 if (bestdist > dist)
3861 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);
3862 // if the nearest point is near or behind the plane, we want this
3863 // plane, otherwise the plane is useless as it won't cull anything
3864 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3866 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3867 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3874 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3878 RSurf_ActiveWorldEntity();
3880 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3883 GL_CullFace(GL_NONE);
3884 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3885 for (;mesh;mesh = mesh->next)
3887 if (!mesh->sidetotals[r_shadow_shadowmapside])
3889 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3890 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3891 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3895 else if (r_refdef.scene.worldentity->model)
3896 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);
3898 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3901 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3906 int surfacelistindex;
3907 msurface_t *surface;
3909 RSurf_ActiveWorldEntity();
3911 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3914 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3915 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3916 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3917 for (;mesh;mesh = mesh->next)
3919 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3920 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3921 GL_LockArrays(0, mesh->numverts);
3922 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3924 // increment stencil if frontface is infront of depthbuffer
3925 GL_CullFace(r_refdef.view.cullface_back);
3926 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3927 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3928 // decrement stencil if backface is infront of depthbuffer
3929 GL_CullFace(r_refdef.view.cullface_front);
3930 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3932 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3934 // decrement stencil if backface is behind depthbuffer
3935 GL_CullFace(r_refdef.view.cullface_front);
3936 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3937 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3938 // increment stencil if frontface is behind depthbuffer
3939 GL_CullFace(r_refdef.view.cullface_back);
3940 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3942 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3943 GL_LockArrays(0, 0);
3947 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3949 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3950 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3952 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3953 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3954 if (CHECKPVSBIT(trispvs, t))
3955 shadowmarklist[numshadowmark++] = t;
3957 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);
3959 else if (numsurfaces)
3960 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3962 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3965 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3967 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3968 vec_t relativeshadowradius;
3969 RSurf_ActiveModelEntity(ent, false, false);
3970 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3971 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3972 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3973 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3974 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3975 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3976 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3977 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3978 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3980 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3983 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3984 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3987 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3989 // set up properties for rendering light onto this entity
3990 RSurf_ActiveModelEntity(ent, true, true);
3991 GL_AlphaTest(false);
3992 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3993 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3994 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3995 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3996 switch(r_shadow_lightingrendermode)
3998 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3999 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
4006 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4008 if (!r_refdef.scene.worldmodel->DrawLight)
4011 // set up properties for rendering light onto this entity
4012 RSurf_ActiveWorldEntity();
4013 GL_AlphaTest(false);
4014 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4015 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4016 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4017 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4018 switch(r_shadow_lightingrendermode)
4020 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
4021 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
4027 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
4029 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4032 void R_Shadow_DrawEntityLight(entity_render_t *ent)
4034 dp_model_t *model = ent->model;
4035 if (!model->DrawLight)
4038 R_Shadow_SetupEntityLight(ent);
4040 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4042 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4045 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
4049 int numleafs, numsurfaces;
4050 int *leaflist, *surfacelist;
4051 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
4052 int numlightentities;
4053 int numlightentities_noselfshadow;
4054 int numshadowentities;
4055 int numshadowentities_noselfshadow;
4056 static entity_render_t *lightentities[MAX_EDICTS];
4057 static entity_render_t *shadowentities[MAX_EDICTS];
4058 static unsigned char entitysides[MAX_EDICTS];
4059 int lightentities_noselfshadow;
4060 int shadowentities_noselfshadow;
4061 vec3_t nearestpoint;
4063 qboolean castshadows;
4066 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4067 // skip lights that are basically invisible (color 0 0 0)
4068 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
4071 // loading is done before visibility checks because loading should happen
4072 // all at once at the start of a level, not when it stalls gameplay.
4073 // (especially important to benchmarks)
4075 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4077 if (rtlight->compiled)
4078 R_RTLight_Uncompile(rtlight);
4079 R_RTLight_Compile(rtlight);
4083 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
4085 // look up the light style value at this time
4086 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4087 VectorScale(rtlight->color, f, rtlight->currentcolor);
4089 if (rtlight->selected)
4091 f = 2 + sin(realtime * M_PI * 4.0);
4092 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4096 // if lightstyle is currently off, don't draw the light
4097 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4100 // if the light box is offscreen, skip it
4101 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4104 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
4105 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
4107 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4109 // compiled light, world available and can receive realtime lighting
4110 // retrieve leaf information
4111 numleafs = rtlight->static_numleafs;
4112 leaflist = rtlight->static_leaflist;
4113 leafpvs = rtlight->static_leafpvs;
4114 numsurfaces = rtlight->static_numsurfaces;
4115 surfacelist = rtlight->static_surfacelist;
4116 surfacesides = NULL;
4117 shadowtrispvs = rtlight->static_shadowtrispvs;
4118 lighttrispvs = rtlight->static_lighttrispvs;
4120 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4122 // dynamic light, world available and can receive realtime lighting
4123 // calculate lit surfaces and leafs
4124 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);
4125 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);
4126 leaflist = r_shadow_buffer_leaflist;
4127 leafpvs = r_shadow_buffer_leafpvs;
4128 surfacelist = r_shadow_buffer_surfacelist;
4129 surfacesides = r_shadow_buffer_surfacesides;
4130 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4131 lighttrispvs = r_shadow_buffer_lighttrispvs;
4132 // if the reduced leaf bounds are offscreen, skip it
4133 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4144 surfacesides = NULL;
4145 shadowtrispvs = NULL;
4146 lighttrispvs = NULL;
4148 // check if light is illuminating any visible leafs
4151 for (i = 0;i < numleafs;i++)
4152 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4157 // set up a scissor rectangle for this light
4158 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4161 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4163 // make a list of lit entities and shadow casting entities
4164 numlightentities = 0;
4165 numlightentities_noselfshadow = 0;
4166 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4167 numshadowentities = 0;
4168 numshadowentities_noselfshadow = 0;
4169 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4171 // add dynamic entities that are lit by the light
4172 if (r_drawentities.integer)
4174 for (i = 0;i < r_refdef.scene.numentities;i++)
4177 entity_render_t *ent = r_refdef.scene.entities[i];
4179 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4181 // skip the object entirely if it is not within the valid
4182 // shadow-casting region (which includes the lit region)
4183 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4185 if (!(model = ent->model))
4187 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4189 // this entity wants to receive light, is visible, and is
4190 // inside the light box
4191 // TODO: check if the surfaces in the model can receive light
4192 // so now check if it's in a leaf seen by the light
4193 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))
4195 if (ent->flags & RENDER_NOSELFSHADOW)
4196 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4198 lightentities[numlightentities++] = ent;
4199 // since it is lit, it probably also casts a shadow...
4200 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4201 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4202 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4204 // note: exterior models without the RENDER_NOSELFSHADOW
4205 // flag still create a RENDER_NOSELFSHADOW shadow but
4206 // are lit normally, this means that they are
4207 // self-shadowing but do not shadow other
4208 // RENDER_NOSELFSHADOW entities such as the gun
4209 // (very weird, but keeps the player shadow off the gun)
4210 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4211 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4213 shadowentities[numshadowentities++] = ent;
4216 else if (ent->flags & RENDER_SHADOW)
4218 // this entity is not receiving light, but may still need to
4220 // TODO: check if the surfaces in the model can cast shadow
4221 // now check if it is in a leaf seen by the light
4222 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))
4224 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4225 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4226 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4228 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4229 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4231 shadowentities[numshadowentities++] = ent;
4237 // return if there's nothing at all to light
4238 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4241 // don't let sound skip if going slow
4242 if (r_refdef.scene.extraupdate)
4245 // make this the active rtlight for rendering purposes
4246 R_Shadow_RenderMode_ActiveLight(rtlight);
4247 // count this light in the r_speeds
4248 r_refdef.stats.lights++;
4250 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4252 // optionally draw visible shape of the shadow volumes
4253 // for performance analysis by level designers
4254 R_Shadow_RenderMode_VisibleShadowVolumes();
4256 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4257 for (i = 0;i < numshadowentities;i++)
4258 R_Shadow_DrawEntityShadow(shadowentities[i]);
4259 for (i = 0;i < numshadowentities_noselfshadow;i++)
4260 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4263 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4265 // optionally draw the illuminated areas
4266 // for performance analysis by level designers
4267 R_Shadow_RenderMode_VisibleLighting(false, false);
4269 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4270 for (i = 0;i < numlightentities;i++)
4271 R_Shadow_DrawEntityLight(lightentities[i]);
4272 for (i = 0;i < numlightentities_noselfshadow;i++)
4273 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4276 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4278 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4279 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4280 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4281 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4283 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4284 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4285 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4287 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4293 int receivermask = 0;
4294 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4295 Matrix4x4_Abs(&radiustolight);
4297 r_shadow_shadowmaplod = 0;
4298 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4299 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4300 r_shadow_shadowmaplod = i;
4302 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
4303 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
4305 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4307 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4311 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4313 castermask = rtlight->static_shadowmap_casters;
4314 receivermask = rtlight->static_shadowmap_receivers;
4318 for(i = 0;i < numsurfaces;i++)
4320 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4321 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4322 castermask |= surfacesides[i];
4323 receivermask |= surfacesides[i];
4327 if (receivermask < 0x3F)
4329 for (i = 0;i < numlightentities;i++)
4330 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4331 if (receivermask < 0x3F)
4332 for(i = 0; i < numlightentities_noselfshadow;i++)
4333 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4336 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4340 for (i = 0;i < numshadowentities;i++)
4341 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4342 for (i = 0;i < numshadowentities_noselfshadow;i++)
4343 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4346 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4348 // render shadow casters into 6 sided depth texture
4349 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4351 R_Shadow_RenderMode_ShadowMap(side, true, size);
4352 if (! (castermask & (1 << side))) continue;
4354 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4355 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4356 R_Shadow_DrawEntityShadow(shadowentities[i]);
4359 if (numlightentities_noselfshadow)
4361 // render lighting using the depth texture as shadowmap
4362 // draw lighting in the unmasked areas
4363 R_Shadow_RenderMode_Lighting(false, false, true);
4364 for (i = 0;i < numlightentities_noselfshadow;i++)
4365 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4368 // render shadow casters into 6 sided depth texture
4369 if (numshadowentities_noselfshadow)
4371 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4373 R_Shadow_RenderMode_ShadowMap(side, false, size);
4374 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4375 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4379 // render lighting using the depth texture as shadowmap
4380 // draw lighting in the unmasked areas
4381 R_Shadow_RenderMode_Lighting(false, false, true);
4382 // draw lighting in the unmasked areas
4384 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4385 for (i = 0;i < numlightentities;i++)
4386 R_Shadow_DrawEntityLight(lightentities[i]);
4388 else if (castshadows && vid.stencil)
4390 // draw stencil shadow volumes to mask off pixels that are in shadow
4391 // so that they won't receive lighting
4392 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4393 R_Shadow_ClearStencil();
4395 if (numsurfaces + numshadowentities)
4398 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4399 for (i = 0;i < numshadowentities;i++)
4400 R_Shadow_DrawEntityShadow(shadowentities[i]);
4403 if (numlightentities_noselfshadow)
4405 // draw lighting in the unmasked areas
4406 R_Shadow_RenderMode_Lighting(true, false, false);
4407 for (i = 0;i < numlightentities_noselfshadow;i++)
4408 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4410 // optionally draw the illuminated areas
4411 // for performance analysis by level designers
4412 if (r_showlighting.integer && r_refdef.view.showdebug)
4414 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4415 for (i = 0;i < numlightentities_noselfshadow;i++)
4416 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4418 for (i = 0;i < numshadowentities_noselfshadow;i++)
4419 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4422 if (numsurfaces + numlightentities)
4424 // draw lighting in the unmasked areas
4425 R_Shadow_RenderMode_Lighting(true, false, false);
4427 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4428 for (i = 0;i < numlightentities;i++)
4429 R_Shadow_DrawEntityLight(lightentities[i]);
4434 // draw lighting in the unmasked areas
4435 R_Shadow_RenderMode_Lighting(false, false, false);
4437 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4438 for (i = 0;i < numlightentities;i++)
4439 R_Shadow_DrawEntityLight(lightentities[i]);
4440 for (i = 0;i < numlightentities_noselfshadow;i++)
4441 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4445 void R_Shadow_DrawLightSprites(void);
4446 void R_ShadowVolumeLighting(qboolean visible)
4455 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4456 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != r_shadow_shadowmapping.integer ||
4457 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4458 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4459 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4460 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4461 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4462 R_Shadow_FreeShadowMaps();
4464 if (r_editlights.integer)
4465 R_Shadow_DrawLightSprites();
4467 R_Shadow_RenderMode_Begin();
4469 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4470 if (r_shadow_debuglight.integer >= 0)
4472 lightindex = r_shadow_debuglight.integer;
4473 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4474 if (light && (light->flags & flag))
4475 R_DrawRTLight(&light->rtlight, visible);
4479 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4480 for (lightindex = 0;lightindex < range;lightindex++)
4482 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4483 if (light && (light->flags & flag))
4484 R_DrawRTLight(&light->rtlight, visible);
4487 if (r_refdef.scene.rtdlight)
4489 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4490 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4492 else if(gl_flashblend.integer)
4494 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4496 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4497 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4498 VectorScale(rtlight->color, f, rtlight->currentcolor);
4502 R_Shadow_RenderMode_End();
4505 extern const float r_screenvertex3f[12];
4506 extern void R_SetupView(qboolean allowwaterclippingplane);
4507 extern void R_ResetViewRendering3D(void);
4508 extern void R_ResetViewRendering2D(void);
4509 extern cvar_t r_shadows;
4510 extern cvar_t r_shadows_darken;
4511 extern cvar_t r_shadows_drawafterrtlighting;
4512 extern cvar_t r_shadows_castfrombmodels;
4513 extern cvar_t r_shadows_throwdistance;
4514 extern cvar_t r_shadows_throwdirection;
4515 void R_DrawModelShadows(void)
4518 float relativethrowdistance;
4519 entity_render_t *ent;
4520 vec3_t relativelightorigin;
4521 vec3_t relativelightdirection;
4522 vec3_t relativeshadowmins, relativeshadowmaxs;
4523 vec3_t tmp, shadowdir;
4525 if (!r_drawentities.integer || !vid.stencil)
4529 R_ResetViewRendering3D();
4530 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4531 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4532 R_Shadow_RenderMode_Begin();
4533 R_Shadow_RenderMode_ActiveLight(NULL);
4534 r_shadow_lightscissor[0] = r_refdef.view.x;
4535 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4536 r_shadow_lightscissor[2] = r_refdef.view.width;
4537 r_shadow_lightscissor[3] = r_refdef.view.height;
4538 R_Shadow_RenderMode_StencilShadowVolumes(false);
4541 if (r_shadows.integer == 2)
4543 Math_atov(r_shadows_throwdirection.string, shadowdir);
4544 VectorNormalize(shadowdir);
4547 R_Shadow_ClearStencil();
4549 for (i = 0;i < r_refdef.scene.numentities;i++)
4551 ent = r_refdef.scene.entities[i];
4553 // cast shadows from anything of the map (submodels are optional)
4554 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4556 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4557 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4558 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4559 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4560 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4563 if(ent->entitynumber != 0)
4565 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4566 int entnum, entnum2, recursion;
4567 entnum = entnum2 = ent->entitynumber;
4568 for(recursion = 32; recursion > 0; --recursion)
4570 entnum2 = cl.entities[entnum].state_current.tagentity;
4571 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4576 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4578 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4579 // transform into modelspace of OUR entity
4580 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4581 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4584 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4587 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4590 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4591 RSurf_ActiveModelEntity(ent, false, false);
4592 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4593 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4597 // not really the right mode, but this will disable any silly stencil features
4598 R_Shadow_RenderMode_End();
4600 // set up ortho view for rendering this pass
4601 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4602 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4603 //GL_ScissorTest(true);
4604 //R_Mesh_Matrix(&identitymatrix);
4605 //R_Mesh_ResetTextureState();
4606 R_ResetViewRendering2D();
4607 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4608 R_Mesh_ColorPointer(NULL, 0, 0);
4609 R_SetupGenericShader(false);
4611 // set up a darkening blend on shadowed areas
4612 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4613 //GL_DepthRange(0, 1);
4614 //GL_DepthTest(false);
4615 //GL_DepthMask(false);
4616 //GL_PolygonOffset(0, 0);CHECKGLERROR
4617 GL_Color(0, 0, 0, r_shadows_darken.value);
4618 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4619 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4620 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4621 qglStencilMask(~0);CHECKGLERROR
4622 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4623 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4625 // apply the blend to the shadowed areas
4626 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4628 // restore the viewport
4629 R_SetViewport(&r_refdef.view.viewport);
4631 // restore other state to normal
4632 //R_Shadow_RenderMode_End();
4635 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4638 vec3_t centerorigin;
4640 // if it's too close, skip it
4641 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4643 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4646 if (usequery && r_numqueries + 2 <= r_maxqueries)
4648 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4649 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4650 // 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
4651 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4654 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4655 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4656 qglDepthFunc(GL_ALWAYS);
4657 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4658 R_Mesh_VertexPointer(vertex3f, 0, 0);
4659 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4660 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4661 qglDepthFunc(GL_LEQUAL);
4662 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4663 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4664 R_Mesh_VertexPointer(vertex3f, 0, 0);
4665 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4666 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4669 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4672 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4674 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4677 GLint allpixels = 0, visiblepixels = 0;
4678 // now we have to check the query result
4679 if (rtlight->corona_queryindex_visiblepixels)
4682 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4683 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4685 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4686 if (visiblepixels < 1 || allpixels < 1)
4688 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4689 cscale *= rtlight->corona_visibility;
4693 // FIXME: these traces should scan all render entities instead of cl.world
4694 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4697 VectorScale(rtlight->currentcolor, cscale, color);
4698 if (VectorLength(color) > (1.0f / 256.0f))
4701 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4704 VectorNegate(color, color);
4705 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4707 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4708 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);
4709 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4711 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4715 void R_DrawCoronas(void)
4723 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4725 if (r_waterstate.renderingscene)
4727 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4728 R_Mesh_Matrix(&identitymatrix);
4730 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4732 // check occlusion of coronas
4733 // use GL_ARB_occlusion_query if available
4734 // otherwise use raytraces
4736 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4739 GL_ColorMask(0,0,0,0);
4740 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4741 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4744 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4745 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4747 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4750 RSurf_ActiveWorldEntity();
4751 GL_BlendFunc(GL_ONE, GL_ZERO);
4752 GL_CullFace(GL_NONE);
4753 GL_DepthMask(false);
4754 GL_DepthRange(0, 1);
4755 GL_PolygonOffset(0, 0);
4757 R_Mesh_ColorPointer(NULL, 0, 0);
4758 R_Mesh_ResetTextureState();
4759 R_SetupGenericShader(false);
4761 for (lightindex = 0;lightindex < range;lightindex++)
4763 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4766 rtlight = &light->rtlight;
4767 rtlight->corona_visibility = 0;
4768 rtlight->corona_queryindex_visiblepixels = 0;
4769 rtlight->corona_queryindex_allpixels = 0;
4770 if (!(rtlight->flags & flag))
4772 if (rtlight->corona <= 0)
4774 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4776 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4778 for (i = 0;i < r_refdef.scene.numlights;i++)
4780 rtlight = r_refdef.scene.lights[i];
4781 rtlight->corona_visibility = 0;
4782 rtlight->corona_queryindex_visiblepixels = 0;
4783 rtlight->corona_queryindex_allpixels = 0;
4784 if (!(rtlight->flags & flag))
4786 if (rtlight->corona <= 0)
4788 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4791 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4793 // now draw the coronas using the query data for intensity info
4794 for (lightindex = 0;lightindex < range;lightindex++)
4796 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4799 rtlight = &light->rtlight;
4800 if (rtlight->corona_visibility <= 0)
4802 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4804 for (i = 0;i < r_refdef.scene.numlights;i++)
4806 rtlight = r_refdef.scene.lights[i];
4807 if (rtlight->corona_visibility <= 0)
4809 if (gl_flashblend.integer)
4810 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4812 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4818 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4819 typedef struct suffixinfo_s
4822 qboolean flipx, flipy, flipdiagonal;
4825 static suffixinfo_t suffix[3][6] =
4828 {"px", false, false, false},
4829 {"nx", false, false, false},
4830 {"py", false, false, false},
4831 {"ny", false, false, false},
4832 {"pz", false, false, false},
4833 {"nz", false, false, false}
4836 {"posx", false, false, false},
4837 {"negx", false, false, false},
4838 {"posy", false, false, false},
4839 {"negy", false, false, false},
4840 {"posz", false, false, false},
4841 {"negz", false, false, false}
4844 {"rt", true, false, true},
4845 {"lf", false, true, true},
4846 {"ft", true, true, false},
4847 {"bk", false, false, false},
4848 {"up", true, false, true},
4849 {"dn", true, false, true}
4853 static int componentorder[4] = {0, 1, 2, 3};
4855 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4857 int i, j, cubemapsize;
4858 unsigned char *cubemappixels, *image_buffer;
4859 rtexture_t *cubemaptexture;
4861 // must start 0 so the first loadimagepixels has no requested width/height
4863 cubemappixels = NULL;
4864 cubemaptexture = NULL;
4865 // keep trying different suffix groups (posx, px, rt) until one loads
4866 for (j = 0;j < 3 && !cubemappixels;j++)
4868 // load the 6 images in the suffix group
4869 for (i = 0;i < 6;i++)
4871 // generate an image name based on the base and and suffix
4872 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4874 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4876 // an image loaded, make sure width and height are equal
4877 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4879 // if this is the first image to load successfully, allocate the cubemap memory
4880 if (!cubemappixels && image_width >= 1)
4882 cubemapsize = image_width;
4883 // note this clears to black, so unavailable sides are black
4884 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4886 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4888 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);
4891 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4893 Mem_Free(image_buffer);
4897 // if a cubemap loaded, upload it
4900 if (developer_loading.integer)
4901 Con_Printf("loading cubemap \"%s\"\n", basename);
4903 if (!r_shadow_filters_texturepool)
4904 r_shadow_filters_texturepool = R_AllocTexturePool();
4905 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4906 Mem_Free(cubemappixels);
4910 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4911 if (developer_loading.integer)
4913 Con_Printf("(tried tried images ");
4914 for (j = 0;j < 3;j++)
4915 for (i = 0;i < 6;i++)
4916 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4917 Con_Print(" and was unable to find any of them).\n");
4920 return cubemaptexture;
4923 rtexture_t *R_Shadow_Cubemap(const char *basename)
4926 for (i = 0;i < numcubemaps;i++)
4927 if (!strcasecmp(cubemaps[i].basename, basename))
4928 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4929 if (i >= MAX_CUBEMAPS)
4930 return r_texture_whitecube;
4932 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4933 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4934 return cubemaps[i].texture;
4937 void R_Shadow_FreeCubemaps(void)
4940 for (i = 0;i < numcubemaps;i++)
4942 if (developer_loading.integer)
4943 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4944 if (cubemaps[i].texture)
4945 R_FreeTexture(cubemaps[i].texture);
4949 R_FreeTexturePool(&r_shadow_filters_texturepool);
4952 dlight_t *R_Shadow_NewWorldLight(void)
4954 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4957 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)
4960 // validate parameters
4961 if (style < 0 || style >= MAX_LIGHTSTYLES)
4963 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4969 // copy to light properties
4970 VectorCopy(origin, light->origin);
4971 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4972 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4973 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4975 light->color[0] = max(color[0], 0);
4976 light->color[1] = max(color[1], 0);
4977 light->color[2] = max(color[2], 0);
4979 light->color[0] = color[0];
4980 light->color[1] = color[1];
4981 light->color[2] = color[2];
4982 light->radius = max(radius, 0);
4983 light->style = style;
4984 light->shadow = shadowenable;
4985 light->corona = corona;
4986 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4987 light->coronasizescale = coronasizescale;
4988 light->ambientscale = ambientscale;
4989 light->diffusescale = diffusescale;
4990 light->specularscale = specularscale;
4991 light->flags = flags;
4993 // update renderable light data
4994 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4995 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);
4998 void R_Shadow_FreeWorldLight(dlight_t *light)
5000 if (r_shadow_selectedlight == light)
5001 r_shadow_selectedlight = NULL;
5002 R_RTLight_Uncompile(&light->rtlight);
5003 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5006 void R_Shadow_ClearWorldLights(void)
5010 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5011 for (lightindex = 0;lightindex < range;lightindex++)
5013 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5015 R_Shadow_FreeWorldLight(light);
5017 r_shadow_selectedlight = NULL;
5018 R_Shadow_FreeCubemaps();
5021 void R_Shadow_SelectLight(dlight_t *light)
5023 if (r_shadow_selectedlight)
5024 r_shadow_selectedlight->selected = false;
5025 r_shadow_selectedlight = light;
5026 if (r_shadow_selectedlight)
5027 r_shadow_selectedlight->selected = true;
5030 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5032 // this is never batched (there can be only one)
5034 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5035 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5036 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5039 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5044 skinframe_t *skinframe;
5047 // this is never batched (due to the ent parameter changing every time)
5048 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5049 const dlight_t *light = (dlight_t *)ent;
5052 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5055 VectorScale(light->color, intensity, spritecolor);
5056 if (VectorLength(spritecolor) < 0.1732f)
5057 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5058 if (VectorLength(spritecolor) > 1.0f)
5059 VectorNormalize(spritecolor);
5061 // draw light sprite
5062 if (light->cubemapname[0] && !light->shadow)
5063 skinframe = r_editlights_sprcubemapnoshadowlight;
5064 else if (light->cubemapname[0])
5065 skinframe = r_editlights_sprcubemaplight;
5066 else if (!light->shadow)
5067 skinframe = r_editlights_sprnoshadowlight;
5069 skinframe = r_editlights_sprlight;
5071 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);
5072 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5074 // draw selection sprite if light is selected
5075 if (light->selected)
5077 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5078 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5079 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5083 void R_Shadow_DrawLightSprites(void)
5087 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5088 for (lightindex = 0;lightindex < range;lightindex++)
5090 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5092 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5094 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5097 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5102 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5103 if (lightindex >= range)
5105 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5108 rtlight = &light->rtlight;
5109 //if (!(rtlight->flags & flag))
5111 VectorCopy(rtlight->shadoworigin, origin);
5112 *radius = rtlight->radius;
5113 VectorCopy(rtlight->color, color);
5117 void R_Shadow_SelectLightInView(void)
5119 float bestrating, rating, temp[3];
5123 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5126 for (lightindex = 0;lightindex < range;lightindex++)
5128 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5131 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5132 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5135 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5136 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5138 bestrating = rating;
5143 R_Shadow_SelectLight(best);
5146 void R_Shadow_LoadWorldLights(void)
5148 int n, a, style, shadow, flags;
5149 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5150 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5151 if (cl.worldmodel == NULL)
5153 Con_Print("No map loaded.\n");
5156 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5157 strlcat (name, ".rtlights", sizeof (name));
5158 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5168 for (;COM_Parse(t, true) && strcmp(
5169 if (COM_Parse(t, true))
5171 if (com_token[0] == '!')
5174 origin[0] = atof(com_token+1);
5177 origin[0] = atof(com_token);
5182 while (*s && *s != '\n' && *s != '\r')
5188 // check for modifier flags
5195 #if _MSC_VER >= 1400
5196 #define sscanf sscanf_s
5198 cubemapname[sizeof(cubemapname)-1] = 0;
5199 #if MAX_QPATH != 128
5200 #error update this code if MAX_QPATH changes
5202 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
5203 #if _MSC_VER >= 1400
5204 , sizeof(cubemapname)
5206 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5209 flags = LIGHTFLAG_REALTIMEMODE;
5217 coronasizescale = 0.25f;
5219 VectorClear(angles);
5222 if (a < 9 || !strcmp(cubemapname, "\"\""))
5224 // remove quotes on cubemapname
5225 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5228 namelen = strlen(cubemapname) - 2;
5229 memmove(cubemapname, cubemapname + 1, namelen);
5230 cubemapname[namelen] = '\0';
5234 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);
5237 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5245 Con_Printf("invalid rtlights file \"%s\"\n", name);
5246 Mem_Free(lightsstring);
5250 void R_Shadow_SaveWorldLights(void)
5254 size_t bufchars, bufmaxchars;
5256 char name[MAX_QPATH];
5257 char line[MAX_INPUTLINE];
5258 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5259 // I hate lines which are 3 times my screen size :( --blub
5262 if (cl.worldmodel == NULL)
5264 Con_Print("No map loaded.\n");
5267 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5268 strlcat (name, ".rtlights", sizeof (name));
5269 bufchars = bufmaxchars = 0;
5271 for (lightindex = 0;lightindex < range;lightindex++)
5273 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5276 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5277 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);
5278 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5279 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]);
5281 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);
5282 if (bufchars + strlen(line) > bufmaxchars)
5284 bufmaxchars = bufchars + strlen(line) + 2048;
5286 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5290 memcpy(buf, oldbuf, bufchars);
5296 memcpy(buf + bufchars, line, strlen(line));
5297 bufchars += strlen(line);
5301 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5306 void R_Shadow_LoadLightsFile(void)
5309 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5310 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5311 if (cl.worldmodel == NULL)
5313 Con_Print("No map loaded.\n");
5316 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5317 strlcat (name, ".lights", sizeof (name));
5318 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5326 while (*s && *s != '\n' && *s != '\r')
5332 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);
5336 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);
5339 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5340 radius = bound(15, radius, 4096);
5341 VectorScale(color, (2.0f / (8388608.0f)), color);
5342 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5350 Con_Printf("invalid lights file \"%s\"\n", name);
5351 Mem_Free(lightsstring);
5355 // tyrlite/hmap2 light types in the delay field
5356 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5358 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5360 int entnum, style, islight, skin, pflags, effects, type, n;
5363 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5364 char key[256], value[MAX_INPUTLINE];
5366 if (cl.worldmodel == NULL)
5368 Con_Print("No map loaded.\n");
5371 // try to load a .ent file first
5372 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5373 strlcat (key, ".ent", sizeof (key));
5374 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5375 // and if that is not found, fall back to the bsp file entity string
5377 data = cl.worldmodel->brush.entities;
5380 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5382 type = LIGHTTYPE_MINUSX;
5383 origin[0] = origin[1] = origin[2] = 0;
5384 originhack[0] = originhack[1] = originhack[2] = 0;
5385 angles[0] = angles[1] = angles[2] = 0;
5386 color[0] = color[1] = color[2] = 1;
5387 light[0] = light[1] = light[2] = 1;light[3] = 300;
5388 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5398 if (!COM_ParseToken_Simple(&data, false, false))
5400 if (com_token[0] == '}')
5401 break; // end of entity
5402 if (com_token[0] == '_')
5403 strlcpy(key, com_token + 1, sizeof(key));
5405 strlcpy(key, com_token, sizeof(key));
5406 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5407 key[strlen(key)-1] = 0;
5408 if (!COM_ParseToken_Simple(&data, false, false))
5410 strlcpy(value, com_token, sizeof(value));
5412 // now that we have the key pair worked out...
5413 if (!strcmp("light", key))
5415 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5419 light[0] = vec[0] * (1.0f / 256.0f);
5420 light[1] = vec[0] * (1.0f / 256.0f);
5421 light[2] = vec[0] * (1.0f / 256.0f);
5427 light[0] = vec[0] * (1.0f / 255.0f);
5428 light[1] = vec[1] * (1.0f / 255.0f);
5429 light[2] = vec[2] * (1.0f / 255.0f);
5433 else if (!strcmp("delay", key))
5435 else if (!strcmp("origin", key))
5436 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5437 else if (!strcmp("angle", key))
5438 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5439 else if (!strcmp("angles", key))
5440 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5441 else if (!strcmp("color", key))
5442 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5443 else if (!strcmp("wait", key))
5444 fadescale = atof(value);
5445 else if (!strcmp("classname", key))
5447 if (!strncmp(value, "light", 5))
5450 if (!strcmp(value, "light_fluoro"))
5455 overridecolor[0] = 1;
5456 overridecolor[1] = 1;
5457 overridecolor[2] = 1;
5459 if (!strcmp(value, "light_fluorospark"))
5464 overridecolor[0] = 1;
5465 overridecolor[1] = 1;
5466 overridecolor[2] = 1;
5468 if (!strcmp(value, "light_globe"))
5473 overridecolor[0] = 1;
5474 overridecolor[1] = 0.8;
5475 overridecolor[2] = 0.4;
5477 if (!strcmp(value, "light_flame_large_yellow"))
5482 overridecolor[0] = 1;
5483 overridecolor[1] = 0.5;
5484 overridecolor[2] = 0.1;
5486 if (!strcmp(value, "light_flame_small_yellow"))
5491 overridecolor[0] = 1;
5492 overridecolor[1] = 0.5;
5493 overridecolor[2] = 0.1;
5495 if (!strcmp(value, "light_torch_small_white"))
5500 overridecolor[0] = 1;
5501 overridecolor[1] = 0.5;
5502 overridecolor[2] = 0.1;
5504 if (!strcmp(value, "light_torch_small_walltorch"))
5509 overridecolor[0] = 1;
5510 overridecolor[1] = 0.5;
5511 overridecolor[2] = 0.1;
5515 else if (!strcmp("style", key))
5516 style = atoi(value);
5517 else if (!strcmp("skin", key))
5518 skin = (int)atof(value);
5519 else if (!strcmp("pflags", key))
5520 pflags = (int)atof(value);
5521 else if (!strcmp("effects", key))
5522 effects = (int)atof(value);
5523 else if (cl.worldmodel->type == mod_brushq3)
5525 if (!strcmp("scale", key))
5526 lightscale = atof(value);
5527 if (!strcmp("fade", key))
5528 fadescale = atof(value);
5533 if (lightscale <= 0)
5537 if (color[0] == color[1] && color[0] == color[2])
5539 color[0] *= overridecolor[0];
5540 color[1] *= overridecolor[1];
5541 color[2] *= overridecolor[2];
5543 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5544 color[0] = color[0] * light[0];
5545 color[1] = color[1] * light[1];
5546 color[2] = color[2] * light[2];
5549 case LIGHTTYPE_MINUSX:
5551 case LIGHTTYPE_RECIPX:
5553 VectorScale(color, (1.0f / 16.0f), color);
5555 case LIGHTTYPE_RECIPXX:
5557 VectorScale(color, (1.0f / 16.0f), color);
5560 case LIGHTTYPE_NONE:
5564 case LIGHTTYPE_MINUSXX:
5567 VectorAdd(origin, originhack, origin);
5569 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);
5572 Mem_Free(entfiledata);
5576 void R_Shadow_SetCursorLocationForView(void)
5579 vec3_t dest, endpos;
5581 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5582 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5583 if (trace.fraction < 1)
5585 dist = trace.fraction * r_editlights_cursordistance.value;
5586 push = r_editlights_cursorpushback.value;
5590 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5591 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5595 VectorClear( endpos );
5597 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5598 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5599 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5602 void R_Shadow_UpdateWorldLightSelection(void)
5604 if (r_editlights.integer)
5606 R_Shadow_SetCursorLocationForView();
5607 R_Shadow_SelectLightInView();
5610 R_Shadow_SelectLight(NULL);
5613 void R_Shadow_EditLights_Clear_f(void)
5615 R_Shadow_ClearWorldLights();
5618 void R_Shadow_EditLights_Reload_f(void)
5622 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5623 R_Shadow_ClearWorldLights();
5624 R_Shadow_LoadWorldLights();
5625 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5627 R_Shadow_LoadLightsFile();
5628 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5629 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5633 void R_Shadow_EditLights_Save_f(void)
5637 R_Shadow_SaveWorldLights();
5640 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5642 R_Shadow_ClearWorldLights();
5643 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5646 void R_Shadow_EditLights_ImportLightsFile_f(void)
5648 R_Shadow_ClearWorldLights();
5649 R_Shadow_LoadLightsFile();
5652 void R_Shadow_EditLights_Spawn_f(void)
5655 if (!r_editlights.integer)
5657 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5660 if (Cmd_Argc() != 1)
5662 Con_Print("r_editlights_spawn does not take parameters\n");
5665 color[0] = color[1] = color[2] = 1;
5666 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5669 void R_Shadow_EditLights_Edit_f(void)
5671 vec3_t origin, angles, color;
5672 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5673 int style, shadows, flags, normalmode, realtimemode;
5674 char cubemapname[MAX_INPUTLINE];
5675 if (!r_editlights.integer)
5677 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5680 if (!r_shadow_selectedlight)
5682 Con_Print("No selected light.\n");
5685 VectorCopy(r_shadow_selectedlight->origin, origin);
5686 VectorCopy(r_shadow_selectedlight->angles, angles);
5687 VectorCopy(r_shadow_selectedlight->color, color);
5688 radius = r_shadow_selectedlight->radius;
5689 style = r_shadow_selectedlight->style;
5690 if (r_shadow_selectedlight->cubemapname)
5691 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5694 shadows = r_shadow_selectedlight->shadow;
5695 corona = r_shadow_selectedlight->corona;
5696 coronasizescale = r_shadow_selectedlight->coronasizescale;
5697 ambientscale = r_shadow_selectedlight->ambientscale;
5698 diffusescale = r_shadow_selectedlight->diffusescale;
5699 specularscale = r_shadow_selectedlight->specularscale;
5700 flags = r_shadow_selectedlight->flags;
5701 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5702 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5703 if (!strcmp(Cmd_Argv(1), "origin"))
5705 if (Cmd_Argc() != 5)
5707 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5710 origin[0] = atof(Cmd_Argv(2));
5711 origin[1] = atof(Cmd_Argv(3));
5712 origin[2] = atof(Cmd_Argv(4));
5714 else if (!strcmp(Cmd_Argv(1), "originx"))
5716 if (Cmd_Argc() != 3)
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 origin[0] = atof(Cmd_Argv(2));
5723 else if (!strcmp(Cmd_Argv(1), "originy"))
5725 if (Cmd_Argc() != 3)
5727 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5730 origin[1] = atof(Cmd_Argv(2));
5732 else if (!strcmp(Cmd_Argv(1), "originz"))
5734 if (Cmd_Argc() != 3)
5736 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5739 origin[2] = atof(Cmd_Argv(2));
5741 else if (!strcmp(Cmd_Argv(1), "move"))
5743 if (Cmd_Argc() != 5)
5745 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5748 origin[0] += atof(Cmd_Argv(2));
5749 origin[1] += atof(Cmd_Argv(3));
5750 origin[2] += atof(Cmd_Argv(4));
5752 else if (!strcmp(Cmd_Argv(1), "movex"))
5754 if (Cmd_Argc() != 3)
5756 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5759 origin[0] += atof(Cmd_Argv(2));
5761 else if (!strcmp(Cmd_Argv(1), "movey"))
5763 if (Cmd_Argc() != 3)
5765 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5768 origin[1] += atof(Cmd_Argv(2));
5770 else if (!strcmp(Cmd_Argv(1), "movez"))
5772 if (Cmd_Argc() != 3)
5774 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5777 origin[2] += atof(Cmd_Argv(2));
5779 else if (!strcmp(Cmd_Argv(1), "angles"))
5781 if (Cmd_Argc() != 5)
5783 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5786 angles[0] = atof(Cmd_Argv(2));
5787 angles[1] = atof(Cmd_Argv(3));
5788 angles[2] = atof(Cmd_Argv(4));
5790 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5792 if (Cmd_Argc() != 3)
5794 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5797 angles[0] = atof(Cmd_Argv(2));
5799 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5801 if (Cmd_Argc() != 3)
5803 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5806 angles[1] = atof(Cmd_Argv(2));
5808 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5810 if (Cmd_Argc() != 3)
5812 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5815 angles[2] = atof(Cmd_Argv(2));
5817 else if (!strcmp(Cmd_Argv(1), "color"))
5819 if (Cmd_Argc() != 5)
5821 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5824 color[0] = atof(Cmd_Argv(2));
5825 color[1] = atof(Cmd_Argv(3));
5826 color[2] = atof(Cmd_Argv(4));
5828 else if (!strcmp(Cmd_Argv(1), "radius"))
5830 if (Cmd_Argc() != 3)
5832 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5835 radius = atof(Cmd_Argv(2));
5837 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5839 if (Cmd_Argc() == 3)
5841 double scale = atof(Cmd_Argv(2));
5848 if (Cmd_Argc() != 5)
5850 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5853 color[0] *= atof(Cmd_Argv(2));
5854 color[1] *= atof(Cmd_Argv(3));
5855 color[2] *= atof(Cmd_Argv(4));
5858 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5860 if (Cmd_Argc() != 3)
5862 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5865 radius *= atof(Cmd_Argv(2));
5867 else if (!strcmp(Cmd_Argv(1), "style"))
5869 if (Cmd_Argc() != 3)
5871 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5874 style = atoi(Cmd_Argv(2));
5876 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5880 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5883 if (Cmd_Argc() == 3)
5884 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5888 else if (!strcmp(Cmd_Argv(1), "shadows"))
5890 if (Cmd_Argc() != 3)
5892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5895 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5897 else if (!strcmp(Cmd_Argv(1), "corona"))
5899 if (Cmd_Argc() != 3)
5901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5904 corona = atof(Cmd_Argv(2));
5906 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5908 if (Cmd_Argc() != 3)
5910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5913 coronasizescale = atof(Cmd_Argv(2));
5915 else if (!strcmp(Cmd_Argv(1), "ambient"))
5917 if (Cmd_Argc() != 3)
5919 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5922 ambientscale = atof(Cmd_Argv(2));
5924 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5926 if (Cmd_Argc() != 3)
5928 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5931 diffusescale = atof(Cmd_Argv(2));
5933 else if (!strcmp(Cmd_Argv(1), "specular"))
5935 if (Cmd_Argc() != 3)
5937 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5940 specularscale = atof(Cmd_Argv(2));
5942 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5944 if (Cmd_Argc() != 3)
5946 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5949 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5951 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5953 if (Cmd_Argc() != 3)
5955 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5958 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5962 Con_Print("usage: r_editlights_edit [property] [value]\n");
5963 Con_Print("Selected light's properties:\n");
5964 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5965 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5966 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5967 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5968 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5969 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5970 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5971 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5972 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5973 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5974 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5975 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5976 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5977 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5980 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5981 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5984 void R_Shadow_EditLights_EditAll_f(void)
5990 if (!r_editlights.integer)
5992 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5996 // EditLights doesn't seem to have a "remove" command or something so:
5997 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5998 for (lightindex = 0;lightindex < range;lightindex++)
6000 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6003 R_Shadow_SelectLight(light);
6004 R_Shadow_EditLights_Edit_f();
6008 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6010 int lightnumber, lightcount;
6011 size_t lightindex, range;
6015 if (!r_editlights.integer)
6017 x = vid_conwidth.value - 240;
6019 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6022 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6023 for (lightindex = 0;lightindex < range;lightindex++)
6025 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6028 if (light == r_shadow_selectedlight)
6029 lightnumber = lightindex;
6032 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;
6033 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;
6035 if (r_shadow_selectedlight == NULL)
6037 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;
6038 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;
6039 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;
6040 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;
6041 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;
6042 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;
6043 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;
6044 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;
6045 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;
6046 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;
6047 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;
6048 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;
6049 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;
6050 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;
6051 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;
6054 void R_Shadow_EditLights_ToggleShadow_f(void)
6056 if (!r_editlights.integer)
6058 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6061 if (!r_shadow_selectedlight)
6063 Con_Print("No selected light.\n");
6066 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);
6069 void R_Shadow_EditLights_ToggleCorona_f(void)
6071 if (!r_editlights.integer)
6073 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6076 if (!r_shadow_selectedlight)
6078 Con_Print("No selected light.\n");
6081 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);
6084 void R_Shadow_EditLights_Remove_f(void)
6086 if (!r_editlights.integer)
6088 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6091 if (!r_shadow_selectedlight)
6093 Con_Print("No selected light.\n");
6096 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6097 r_shadow_selectedlight = NULL;
6100 void R_Shadow_EditLights_Help_f(void)
6103 "Documentation on r_editlights system:\n"
6105 "r_editlights : enable/disable editing mode\n"
6106 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6107 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6108 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6109 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6110 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6112 "r_editlights_help : this help\n"
6113 "r_editlights_clear : remove all lights\n"
6114 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6115 "r_editlights_save : save to .rtlights file\n"
6116 "r_editlights_spawn : create a light with default settings\n"
6117 "r_editlights_edit command : edit selected light - more documentation below\n"
6118 "r_editlights_remove : remove selected light\n"
6119 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6120 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6121 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6123 "origin x y z : set light location\n"
6124 "originx x: set x component of light location\n"
6125 "originy y: set y component of light location\n"
6126 "originz z: set z component of light location\n"
6127 "move x y z : adjust light location\n"
6128 "movex x: adjust x component of light location\n"
6129 "movey y: adjust y component of light location\n"
6130 "movez z: adjust z component of light location\n"
6131 "angles x y z : set light angles\n"
6132 "anglesx x: set x component of light angles\n"
6133 "anglesy y: set y component of light angles\n"
6134 "anglesz z: set z component of light angles\n"
6135 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6136 "radius radius : set radius (size) of light\n"
6137 "colorscale grey : multiply color of light (1 does nothing)\n"
6138 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6139 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6140 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6141 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6142 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6143 "shadows 1/0 : turn on/off shadows\n"
6144 "corona n : set corona intensity\n"
6145 "coronasize n : set corona size (0-1)\n"
6146 "ambient n : set ambient intensity (0-1)\n"
6147 "diffuse n : set diffuse intensity (0-1)\n"
6148 "specular n : set specular intensity (0-1)\n"
6149 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6150 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6151 "<nothing> : print light properties to console\n"
6155 void R_Shadow_EditLights_CopyInfo_f(void)
6157 if (!r_editlights.integer)
6159 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6162 if (!r_shadow_selectedlight)
6164 Con_Print("No selected light.\n");
6167 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6168 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6169 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6170 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6171 if (r_shadow_selectedlight->cubemapname)
6172 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6174 r_shadow_bufferlight.cubemapname[0] = 0;
6175 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6176 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6177 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6178 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6179 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6180 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6181 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6184 void R_Shadow_EditLights_PasteInfo_f(void)
6186 if (!r_editlights.integer)
6188 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6191 if (!r_shadow_selectedlight)
6193 Con_Print("No selected light.\n");
6196 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);
6199 void R_Shadow_EditLights_Init(void)
6201 Cvar_RegisterVariable(&r_editlights);
6202 Cvar_RegisterVariable(&r_editlights_cursordistance);
6203 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6204 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6205 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6206 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6207 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6208 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6209 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)");
6210 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6211 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6212 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6213 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)");
6214 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6215 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6216 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6217 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6218 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6219 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6220 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)");
6226 =============================================================================
6230 =============================================================================
6233 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6235 VectorClear(diffusecolor);
6236 VectorClear(diffusenormal);
6238 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6240 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6241 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6244 VectorSet(ambientcolor, 1, 1, 1);
6251 for (i = 0;i < r_refdef.scene.numlights;i++)
6253 light = r_refdef.scene.lights[i];
6254 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6255 f = 1 - VectorLength2(v);
6256 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6257 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);