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_SHADOWMAPRECTANGLE,
162 R_SHADOW_RENDERMODE_SHADOWMAP2D,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 float r_shadow_shadowmap_texturescale[4];
175 float r_shadow_shadowmap_parameters[4];
176 int r_shadow_drawbuffer;
177 int r_shadow_readbuffer;
178 GLuint r_shadow_fborectangle;
179 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
180 GLuint r_shadow_fbo2d;
181 int r_shadow_shadowmode;
182 int r_shadow_shadowmapfilterquality;
183 int r_shadow_shadowmaptexturetype;
184 int r_shadow_shadowmapmaxsize;
185 qboolean r_shadow_shadowmapvsdct;
186 qboolean r_shadow_shadowmapsampler;
187 int r_shadow_shadowmappcf;
188 int r_shadow_shadowmapborder;
189 int r_shadow_lightscissor[4];
191 int maxshadowtriangles;
194 int maxshadowvertices;
195 float *shadowvertex3f;
208 int r_shadow_buffer_numleafpvsbytes;
209 unsigned char *r_shadow_buffer_visitingleafpvs;
210 unsigned char *r_shadow_buffer_leafpvs;
211 int *r_shadow_buffer_leaflist;
213 int r_shadow_buffer_numsurfacepvsbytes;
214 unsigned char *r_shadow_buffer_surfacepvs;
215 int *r_shadow_buffer_surfacelist;
217 int r_shadow_buffer_numshadowtrispvsbytes;
218 unsigned char *r_shadow_buffer_shadowtrispvs;
219 int r_shadow_buffer_numlighttrispvsbytes;
220 unsigned char *r_shadow_buffer_lighttrispvs;
222 rtexturepool_t *r_shadow_texturepool;
223 rtexture_t *r_shadow_attenuationgradienttexture;
224 rtexture_t *r_shadow_attenuation2dtexture;
225 rtexture_t *r_shadow_attenuation3dtexture;
226 rtexture_t *r_shadow_lightcorona;
227 rtexture_t *r_shadow_shadowmaprectangletexture;
228 rtexture_t *r_shadow_shadowmap2dtexture;
229 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
230 rtexture_t *r_shadow_shadowmapcubeprojectiontexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
231 int r_shadow_shadowmapsize; // changes for each light based on distance
232 int r_shadow_shadowmaplod; // changes for each light based on distance
234 // lights are reloaded when this changes
235 char r_shadow_mapname[MAX_QPATH];
237 // used only for light filters (cubemaps)
238 rtexturepool_t *r_shadow_filters_texturepool;
240 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"};
241 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"};
242 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
243 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
244 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)"};
245 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"};
246 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
247 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
248 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
249 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
250 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
251 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
252 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
253 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
254 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
255 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)"};
256 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
257 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
258 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
259 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
260 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)"};
261 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"};
262 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
263 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
264 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"};
265 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
266 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
267 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)"};
268 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"};
269 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "0", "shadowmap texture types: 0 = auto-select, 1 = 2D, 2 = rectangle, 3 = cubemap"};
270 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)"};
271 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
272 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
273 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
274 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
275 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
276 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
277 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
278 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
279 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
280 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
281 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)"};
282 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
283 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
284 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"};
285 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
286 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
287 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
288 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
289 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
290 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
291 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
292 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
293 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
294 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
296 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
297 #define ATTENTABLESIZE 256
298 // 1D gradient, 2D circle and 3D sphere attenuation textures
299 #define ATTEN1DSIZE 32
300 #define ATTEN2DSIZE 64
301 #define ATTEN3DSIZE 32
303 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
304 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
305 static float r_shadow_attentable[ATTENTABLESIZE+1];
307 rtlight_t *r_shadow_compilingrtlight;
308 static memexpandablearray_t r_shadow_worldlightsarray;
309 dlight_t *r_shadow_selectedlight;
310 dlight_t r_shadow_bufferlight;
311 vec3_t r_editlights_cursorlocation;
313 extern int con_vislines;
315 typedef struct cubemapinfo_s
322 #define MAX_CUBEMAPS 256
323 static int numcubemaps;
324 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
326 void R_Shadow_UncompileWorldLights(void);
327 void R_Shadow_ClearWorldLights(void);
328 void R_Shadow_SaveWorldLights(void);
329 void R_Shadow_LoadWorldLights(void);
330 void R_Shadow_LoadLightsFile(void);
331 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
332 void R_Shadow_EditLights_Reload_f(void);
333 void R_Shadow_ValidateCvars(void);
334 static void R_Shadow_MakeTextures(void);
336 // VorteX: custom editor light sprites
337 #define EDLIGHTSPRSIZE 8
338 cachepic_t *r_editlights_sprcursor;
339 cachepic_t *r_editlights_sprlight;
340 cachepic_t *r_editlights_sprnoshadowlight;
341 cachepic_t *r_editlights_sprcubemaplight;
342 cachepic_t *r_editlights_sprcubemapnoshadowlight;
343 cachepic_t *r_editlights_sprselection;
345 void R_Shadow_SetShadowMode(void)
347 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
348 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
349 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
350 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
351 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
352 r_shadow_shadowmaplod = -1;
353 r_shadow_shadowmapsampler = false;
354 r_shadow_shadowmappcf = 0;
355 r_shadow_shadowmode = 0;
356 if(r_shadow_shadowmapping.integer)
358 if(r_shadow_shadowmapfilterquality < 0)
360 if(strstr(gl_vendor, "NVIDIA"))
362 r_shadow_shadowmapsampler = gl_support_arb_shadow;
363 r_shadow_shadowmappcf = 1;
365 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
366 r_shadow_shadowmappcf = 1;
367 else if(strstr(gl_vendor, "ATI"))
368 r_shadow_shadowmappcf = 1;
370 r_shadow_shadowmapsampler = gl_support_arb_shadow;
374 switch (r_shadow_shadowmapfilterquality)
377 r_shadow_shadowmapsampler = gl_support_arb_shadow;
380 r_shadow_shadowmapsampler = gl_support_arb_shadow;
381 r_shadow_shadowmappcf = 1;
384 r_shadow_shadowmappcf = 1;
387 r_shadow_shadowmappcf = 2;
391 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
392 if(r_shadow_shadowmode <= 0)
394 if(!gl_texturerectangle || gl_support_arb_texture_non_power_of_two)
395 r_shadow_shadowmode = 1;
396 else if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
397 r_shadow_shadowmode = 1;
399 r_shadow_shadowmode = 2;
404 void R_Shadow_FreeShadowMaps(void)
408 R_Shadow_SetShadowMode();
410 if (r_shadow_fborectangle)
411 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
412 r_shadow_fborectangle = 0;
416 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
419 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
420 if (r_shadow_fbocubeside[i][0])
421 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
422 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
425 if (r_shadow_shadowmaprectangletexture)
426 R_FreeTexture(r_shadow_shadowmaprectangletexture);
427 r_shadow_shadowmaprectangletexture = NULL;
429 if (r_shadow_shadowmap2dtexture)
430 R_FreeTexture(r_shadow_shadowmap2dtexture);
431 r_shadow_shadowmap2dtexture = NULL;
433 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
434 if (r_shadow_shadowmapcubetexture[i])
435 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
436 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
438 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
439 if (r_shadow_shadowmapcubeprojectiontexture[i])
440 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]);
441 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
446 void r_shadow_start(void)
448 // allocate vertex processing arrays
450 r_shadow_attenuationgradienttexture = NULL;
451 r_shadow_attenuation2dtexture = NULL;
452 r_shadow_attenuation3dtexture = NULL;
453 r_shadow_shadowmode = 0;
454 r_shadow_shadowmaprectangletexture = NULL;
455 r_shadow_shadowmap2dtexture = NULL;
456 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
457 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
458 r_shadow_shadowmapmaxsize = 0;
459 r_shadow_shadowmapsize = 0;
460 r_shadow_shadowmaplod = 0;
461 r_shadow_shadowmapfilterquality = 0;
462 r_shadow_shadowmaptexturetype = 0;
463 r_shadow_shadowmapvsdct = false;
464 r_shadow_shadowmapsampler = false;
465 r_shadow_shadowmappcf = 0;
466 r_shadow_fborectangle = 0;
468 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
470 R_Shadow_FreeShadowMaps();
472 r_shadow_texturepool = NULL;
473 r_shadow_filters_texturepool = NULL;
474 R_Shadow_ValidateCvars();
475 R_Shadow_MakeTextures();
476 maxshadowtriangles = 0;
477 shadowelements = NULL;
478 maxshadowvertices = 0;
479 shadowvertex3f = NULL;
487 shadowmarklist = NULL;
489 r_shadow_buffer_numleafpvsbytes = 0;
490 r_shadow_buffer_visitingleafpvs = NULL;
491 r_shadow_buffer_leafpvs = NULL;
492 r_shadow_buffer_leaflist = NULL;
493 r_shadow_buffer_numsurfacepvsbytes = 0;
494 r_shadow_buffer_surfacepvs = NULL;
495 r_shadow_buffer_surfacelist = NULL;
496 r_shadow_buffer_numshadowtrispvsbytes = 0;
497 r_shadow_buffer_shadowtrispvs = NULL;
498 r_shadow_buffer_numlighttrispvsbytes = 0;
499 r_shadow_buffer_lighttrispvs = NULL;
502 void r_shadow_shutdown(void)
505 R_Shadow_UncompileWorldLights();
507 R_Shadow_FreeShadowMaps();
511 r_shadow_attenuationgradienttexture = NULL;
512 r_shadow_attenuation2dtexture = NULL;
513 r_shadow_attenuation3dtexture = NULL;
514 R_FreeTexturePool(&r_shadow_texturepool);
515 R_FreeTexturePool(&r_shadow_filters_texturepool);
516 maxshadowtriangles = 0;
518 Mem_Free(shadowelements);
519 shadowelements = NULL;
521 Mem_Free(shadowvertex3f);
522 shadowvertex3f = NULL;
525 Mem_Free(vertexupdate);
528 Mem_Free(vertexremap);
534 Mem_Free(shadowmark);
537 Mem_Free(shadowmarklist);
538 shadowmarklist = NULL;
540 r_shadow_buffer_numleafpvsbytes = 0;
541 if (r_shadow_buffer_visitingleafpvs)
542 Mem_Free(r_shadow_buffer_visitingleafpvs);
543 r_shadow_buffer_visitingleafpvs = NULL;
544 if (r_shadow_buffer_leafpvs)
545 Mem_Free(r_shadow_buffer_leafpvs);
546 r_shadow_buffer_leafpvs = NULL;
547 if (r_shadow_buffer_leaflist)
548 Mem_Free(r_shadow_buffer_leaflist);
549 r_shadow_buffer_leaflist = NULL;
550 r_shadow_buffer_numsurfacepvsbytes = 0;
551 if (r_shadow_buffer_surfacepvs)
552 Mem_Free(r_shadow_buffer_surfacepvs);
553 r_shadow_buffer_surfacepvs = NULL;
554 if (r_shadow_buffer_surfacelist)
555 Mem_Free(r_shadow_buffer_surfacelist);
556 r_shadow_buffer_surfacelist = NULL;
557 r_shadow_buffer_numshadowtrispvsbytes = 0;
558 if (r_shadow_buffer_shadowtrispvs)
559 Mem_Free(r_shadow_buffer_shadowtrispvs);
560 r_shadow_buffer_numlighttrispvsbytes = 0;
561 if (r_shadow_buffer_lighttrispvs)
562 Mem_Free(r_shadow_buffer_lighttrispvs);
565 void r_shadow_newmap(void)
567 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
568 R_Shadow_EditLights_Reload_f();
571 void R_Shadow_Help_f(void)
574 "Documentation on r_shadow system:\n"
576 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
577 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
578 "r_shadow_debuglight : render only this light number (-1 = all)\n"
579 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
580 "r_shadow_gloss2intensity : brightness of forced gloss\n"
581 "r_shadow_glossintensity : brightness of textured gloss\n"
582 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
583 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
584 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
585 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
586 "r_shadow_portallight : use portal visibility for static light precomputation\n"
587 "r_shadow_projectdistance : shadow volume projection distance\n"
588 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
589 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
590 "r_shadow_realtime_world : use high quality world lighting mode\n"
591 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
592 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
593 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
594 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
595 "r_shadow_scissor : use scissor optimization\n"
596 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
597 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
598 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
599 "r_showlighting : useful for performance testing; bright = slow!\n"
600 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
602 "r_shadow_help : this help\n"
606 void R_Shadow_Init(void)
608 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
609 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
610 Cvar_RegisterVariable(&r_shadow_usenormalmap);
611 Cvar_RegisterVariable(&r_shadow_debuglight);
612 Cvar_RegisterVariable(&r_shadow_gloss);
613 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
614 Cvar_RegisterVariable(&r_shadow_glossintensity);
615 Cvar_RegisterVariable(&r_shadow_glossexponent);
616 Cvar_RegisterVariable(&r_shadow_glossexact);
617 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
618 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
619 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
620 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
621 Cvar_RegisterVariable(&r_shadow_portallight);
622 Cvar_RegisterVariable(&r_shadow_projectdistance);
623 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
624 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
625 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
626 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
627 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
628 Cvar_RegisterVariable(&r_shadow_realtime_world);
629 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
634 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
635 Cvar_RegisterVariable(&r_shadow_scissor);
636 Cvar_RegisterVariable(&r_shadow_shadowmapping);
637 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
638 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
643 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
644 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
645 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
646 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
647 Cvar_RegisterVariable(&r_shadow_culltriangles);
648 Cvar_RegisterVariable(&r_shadow_polygonfactor);
649 Cvar_RegisterVariable(&r_shadow_polygonoffset);
650 Cvar_RegisterVariable(&r_shadow_texture3d);
651 Cvar_RegisterVariable(&r_coronas);
652 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
653 Cvar_RegisterVariable(&r_coronas_occlusionquery);
654 Cvar_RegisterVariable(&gl_flashblend);
655 Cvar_RegisterVariable(&gl_ext_separatestencil);
656 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
657 if (gamemode == GAME_TENEBRAE)
659 Cvar_SetValue("r_shadow_gloss", 2);
660 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
662 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
663 R_Shadow_EditLights_Init();
664 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
665 maxshadowtriangles = 0;
666 shadowelements = NULL;
667 maxshadowvertices = 0;
668 shadowvertex3f = NULL;
676 shadowmarklist = NULL;
678 r_shadow_buffer_numleafpvsbytes = 0;
679 r_shadow_buffer_visitingleafpvs = NULL;
680 r_shadow_buffer_leafpvs = NULL;
681 r_shadow_buffer_leaflist = NULL;
682 r_shadow_buffer_numsurfacepvsbytes = 0;
683 r_shadow_buffer_surfacepvs = NULL;
684 r_shadow_buffer_surfacelist = NULL;
685 r_shadow_buffer_shadowtrispvs = NULL;
686 r_shadow_buffer_lighttrispvs = NULL;
687 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
690 matrix4x4_t matrix_attenuationxyz =
693 {0.5, 0.0, 0.0, 0.5},
694 {0.0, 0.5, 0.0, 0.5},
695 {0.0, 0.0, 0.5, 0.5},
700 matrix4x4_t matrix_attenuationz =
703 {0.0, 0.0, 0.5, 0.5},
704 {0.0, 0.0, 0.0, 0.5},
705 {0.0, 0.0, 0.0, 0.5},
710 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
712 // make sure shadowelements is big enough for this volume
713 if (maxshadowtriangles < numtriangles)
715 maxshadowtriangles = numtriangles;
717 Mem_Free(shadowelements);
718 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
720 // make sure shadowvertex3f is big enough for this volume
721 if (maxshadowvertices < numvertices)
723 maxshadowvertices = numvertices;
725 Mem_Free(shadowvertex3f);
726 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
730 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
732 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
733 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
734 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
735 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
736 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
738 if (r_shadow_buffer_visitingleafpvs)
739 Mem_Free(r_shadow_buffer_visitingleafpvs);
740 if (r_shadow_buffer_leafpvs)
741 Mem_Free(r_shadow_buffer_leafpvs);
742 if (r_shadow_buffer_leaflist)
743 Mem_Free(r_shadow_buffer_leaflist);
744 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
745 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
746 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
747 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
749 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
751 if (r_shadow_buffer_surfacepvs)
752 Mem_Free(r_shadow_buffer_surfacepvs);
753 if (r_shadow_buffer_surfacelist)
754 Mem_Free(r_shadow_buffer_surfacelist);
755 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
756 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
757 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
759 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
761 if (r_shadow_buffer_shadowtrispvs)
762 Mem_Free(r_shadow_buffer_shadowtrispvs);
763 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
764 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
766 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
768 if (r_shadow_buffer_lighttrispvs)
769 Mem_Free(r_shadow_buffer_lighttrispvs);
770 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
771 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
775 void R_Shadow_PrepareShadowMark(int numtris)
777 // make sure shadowmark is big enough for this volume
778 if (maxshadowmark < numtris)
780 maxshadowmark = numtris;
782 Mem_Free(shadowmark);
784 Mem_Free(shadowmarklist);
785 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
786 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
790 // if shadowmarkcount wrapped we clear the array and adjust accordingly
791 if (shadowmarkcount == 0)
794 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
799 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)
802 int outtriangles = 0, outvertices = 0;
805 float ratio, direction[3], projectvector[3];
807 if (projectdirection)
808 VectorScale(projectdirection, projectdistance, projectvector);
810 VectorClear(projectvector);
812 // create the vertices
813 if (projectdirection)
815 for (i = 0;i < numshadowmarktris;i++)
817 element = inelement3i + shadowmarktris[i] * 3;
818 for (j = 0;j < 3;j++)
820 if (vertexupdate[element[j]] != vertexupdatenum)
822 vertexupdate[element[j]] = vertexupdatenum;
823 vertexremap[element[j]] = outvertices;
824 vertex = invertex3f + element[j] * 3;
825 // project one copy of the vertex according to projectvector
826 VectorCopy(vertex, outvertex3f);
827 VectorAdd(vertex, projectvector, (outvertex3f + 3));
836 for (i = 0;i < numshadowmarktris;i++)
838 element = inelement3i + shadowmarktris[i] * 3;
839 for (j = 0;j < 3;j++)
841 if (vertexupdate[element[j]] != vertexupdatenum)
843 vertexupdate[element[j]] = vertexupdatenum;
844 vertexremap[element[j]] = outvertices;
845 vertex = invertex3f + element[j] * 3;
846 // project one copy of the vertex to the sphere radius of the light
847 // (FIXME: would projecting it to the light box be better?)
848 VectorSubtract(vertex, projectorigin, direction);
849 ratio = projectdistance / VectorLength(direction);
850 VectorCopy(vertex, outvertex3f);
851 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
859 if (r_shadow_frontsidecasting.integer)
861 for (i = 0;i < numshadowmarktris;i++)
863 int remappedelement[3];
865 const int *neighbortriangle;
867 markindex = shadowmarktris[i] * 3;
868 element = inelement3i + markindex;
869 neighbortriangle = inneighbor3i + markindex;
870 // output the front and back triangles
871 outelement3i[0] = vertexremap[element[0]];
872 outelement3i[1] = vertexremap[element[1]];
873 outelement3i[2] = vertexremap[element[2]];
874 outelement3i[3] = vertexremap[element[2]] + 1;
875 outelement3i[4] = vertexremap[element[1]] + 1;
876 outelement3i[5] = vertexremap[element[0]] + 1;
880 // output the sides (facing outward from this triangle)
881 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
883 remappedelement[0] = vertexremap[element[0]];
884 remappedelement[1] = vertexremap[element[1]];
885 outelement3i[0] = remappedelement[1];
886 outelement3i[1] = remappedelement[0];
887 outelement3i[2] = remappedelement[0] + 1;
888 outelement3i[3] = remappedelement[1];
889 outelement3i[4] = remappedelement[0] + 1;
890 outelement3i[5] = remappedelement[1] + 1;
895 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
897 remappedelement[1] = vertexremap[element[1]];
898 remappedelement[2] = vertexremap[element[2]];
899 outelement3i[0] = remappedelement[2];
900 outelement3i[1] = remappedelement[1];
901 outelement3i[2] = remappedelement[1] + 1;
902 outelement3i[3] = remappedelement[2];
903 outelement3i[4] = remappedelement[1] + 1;
904 outelement3i[5] = remappedelement[2] + 1;
909 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
911 remappedelement[0] = vertexremap[element[0]];
912 remappedelement[2] = vertexremap[element[2]];
913 outelement3i[0] = remappedelement[0];
914 outelement3i[1] = remappedelement[2];
915 outelement3i[2] = remappedelement[2] + 1;
916 outelement3i[3] = remappedelement[0];
917 outelement3i[4] = remappedelement[2] + 1;
918 outelement3i[5] = remappedelement[0] + 1;
927 for (i = 0;i < numshadowmarktris;i++)
929 int remappedelement[3];
931 const int *neighbortriangle;
933 markindex = shadowmarktris[i] * 3;
934 element = inelement3i + markindex;
935 neighbortriangle = inneighbor3i + markindex;
936 // output the front and back triangles
937 outelement3i[0] = vertexremap[element[2]];
938 outelement3i[1] = vertexremap[element[1]];
939 outelement3i[2] = vertexremap[element[0]];
940 outelement3i[3] = vertexremap[element[0]] + 1;
941 outelement3i[4] = vertexremap[element[1]] + 1;
942 outelement3i[5] = vertexremap[element[2]] + 1;
946 // output the sides (facing outward from this triangle)
947 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
949 remappedelement[0] = vertexremap[element[0]];
950 remappedelement[1] = vertexremap[element[1]];
951 outelement3i[0] = remappedelement[0];
952 outelement3i[1] = remappedelement[1];
953 outelement3i[2] = remappedelement[1] + 1;
954 outelement3i[3] = remappedelement[0];
955 outelement3i[4] = remappedelement[1] + 1;
956 outelement3i[5] = remappedelement[0] + 1;
961 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
963 remappedelement[1] = vertexremap[element[1]];
964 remappedelement[2] = vertexremap[element[2]];
965 outelement3i[0] = remappedelement[1];
966 outelement3i[1] = remappedelement[2];
967 outelement3i[2] = remappedelement[2] + 1;
968 outelement3i[3] = remappedelement[1];
969 outelement3i[4] = remappedelement[2] + 1;
970 outelement3i[5] = remappedelement[1] + 1;
975 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
977 remappedelement[0] = vertexremap[element[0]];
978 remappedelement[2] = vertexremap[element[2]];
979 outelement3i[0] = remappedelement[2];
980 outelement3i[1] = remappedelement[0];
981 outelement3i[2] = remappedelement[0] + 1;
982 outelement3i[3] = remappedelement[2];
983 outelement3i[4] = remappedelement[0] + 1;
984 outelement3i[5] = remappedelement[2] + 1;
992 *outnumvertices = outvertices;
996 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)
999 int outtriangles = 0, outvertices = 0;
1001 const float *vertex;
1002 float ratio, direction[3], projectvector[3];
1005 if (projectdirection)
1006 VectorScale(projectdirection, projectdistance, projectvector);
1008 VectorClear(projectvector);
1010 for (i = 0;i < numshadowmarktris;i++)
1012 int remappedelement[3];
1014 const int *neighbortriangle;
1016 markindex = shadowmarktris[i] * 3;
1017 neighbortriangle = inneighbor3i + markindex;
1018 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1019 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1020 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1021 if (side[0] + side[1] + side[2] == 0)
1025 element = inelement3i + markindex;
1027 // create the vertices
1028 for (j = 0;j < 3;j++)
1030 if (side[j] + side[j+1] == 0)
1033 if (vertexupdate[k] != vertexupdatenum)
1035 vertexupdate[k] = vertexupdatenum;
1036 vertexremap[k] = outvertices;
1037 vertex = invertex3f + k * 3;
1038 VectorCopy(vertex, outvertex3f);
1039 if (projectdirection)
1041 // project one copy of the vertex according to projectvector
1042 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1046 // project one copy of the vertex to the sphere radius of the light
1047 // (FIXME: would projecting it to the light box be better?)
1048 VectorSubtract(vertex, projectorigin, direction);
1049 ratio = projectdistance / VectorLength(direction);
1050 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1057 // output the sides (facing outward from this triangle)
1060 remappedelement[0] = vertexremap[element[0]];
1061 remappedelement[1] = vertexremap[element[1]];
1062 outelement3i[0] = remappedelement[1];
1063 outelement3i[1] = remappedelement[0];
1064 outelement3i[2] = remappedelement[0] + 1;
1065 outelement3i[3] = remappedelement[1];
1066 outelement3i[4] = remappedelement[0] + 1;
1067 outelement3i[5] = remappedelement[1] + 1;
1074 remappedelement[1] = vertexremap[element[1]];
1075 remappedelement[2] = vertexremap[element[2]];
1076 outelement3i[0] = remappedelement[2];
1077 outelement3i[1] = remappedelement[1];
1078 outelement3i[2] = remappedelement[1] + 1;
1079 outelement3i[3] = remappedelement[2];
1080 outelement3i[4] = remappedelement[1] + 1;
1081 outelement3i[5] = remappedelement[2] + 1;
1088 remappedelement[0] = vertexremap[element[0]];
1089 remappedelement[2] = vertexremap[element[2]];
1090 outelement3i[0] = remappedelement[0];
1091 outelement3i[1] = remappedelement[2];
1092 outelement3i[2] = remappedelement[2] + 1;
1093 outelement3i[3] = remappedelement[0];
1094 outelement3i[4] = remappedelement[2] + 1;
1095 outelement3i[5] = remappedelement[0] + 1;
1102 *outnumvertices = outvertices;
1103 return outtriangles;
1106 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)
1112 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1114 tend = firsttriangle + numtris;
1115 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1117 // surface box entirely inside light box, no box cull
1118 if (projectdirection)
1120 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1122 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1123 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1124 shadowmarklist[numshadowmark++] = t;
1129 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1130 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1131 shadowmarklist[numshadowmark++] = t;
1136 // surface box not entirely inside light box, cull each triangle
1137 if (projectdirection)
1139 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1141 v[0] = invertex3f + e[0] * 3;
1142 v[1] = invertex3f + e[1] * 3;
1143 v[2] = invertex3f + e[2] * 3;
1144 TriangleNormal(v[0], v[1], v[2], normal);
1145 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1146 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1147 shadowmarklist[numshadowmark++] = t;
1152 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1154 v[0] = invertex3f + e[0] * 3;
1155 v[1] = invertex3f + e[1] * 3;
1156 v[2] = invertex3f + e[2] * 3;
1157 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1158 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1159 shadowmarklist[numshadowmark++] = t;
1165 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1170 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1172 // check if the shadow volume intersects the near plane
1174 // a ray between the eye and light origin may intersect the caster,
1175 // indicating that the shadow may touch the eye location, however we must
1176 // test the near plane (a polygon), not merely the eye location, so it is
1177 // easiest to enlarge the caster bounding shape slightly for this.
1183 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)
1185 int i, tris, outverts;
1186 if (projectdistance < 0.1)
1188 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1191 if (!numverts || !nummarktris)
1193 // make sure shadowelements is big enough for this volume
1194 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1195 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1197 if (maxvertexupdate < numverts)
1199 maxvertexupdate = numverts;
1201 Mem_Free(vertexupdate);
1203 Mem_Free(vertexremap);
1204 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1205 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1206 vertexupdatenum = 0;
1209 if (vertexupdatenum == 0)
1211 vertexupdatenum = 1;
1212 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1213 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1216 for (i = 0;i < nummarktris;i++)
1217 shadowmark[marktris[i]] = shadowmarkcount;
1219 if (r_shadow_compilingrtlight)
1221 // if we're compiling an rtlight, capture the mesh
1222 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1223 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1224 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1225 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1229 // decide which type of shadow to generate and set stencil mode
1230 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1231 // generate the sides or a solid volume, depending on type
1232 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1233 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1235 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1236 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1237 r_refdef.stats.lights_shadowtriangles += tris;
1239 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1240 GL_LockArrays(0, outverts);
1241 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1243 // increment stencil if frontface is infront of depthbuffer
1244 GL_CullFace(r_refdef.view.cullface_front);
1245 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1246 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1247 // decrement stencil if backface is infront of depthbuffer
1248 GL_CullFace(r_refdef.view.cullface_back);
1249 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1251 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1253 // decrement stencil if backface is behind depthbuffer
1254 GL_CullFace(r_refdef.view.cullface_front);
1255 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1256 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1257 // increment stencil if frontface is behind depthbuffer
1258 GL_CullFace(r_refdef.view.cullface_back);
1259 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1261 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1262 GL_LockArrays(0, 0);
1267 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
1269 int i, tris = nummarktris;
1272 if (!numverts || !nummarktris)
1274 // make sure shadowelements is big enough for this mesh
1275 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1276 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1278 // gather up the (sparse) triangles into one array
1279 outelement3i = shadowelements;
1280 for (i = 0;i < nummarktris;i++)
1282 element = elements + marktris[i] * 3;
1283 outelement3i[0] = element[0];
1284 outelement3i[1] = element[1];
1285 outelement3i[2] = element[2];
1289 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1290 r_refdef.stats.lights_shadowtriangles += tris;
1291 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1292 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1295 static void R_Shadow_MakeTextures_MakeCorona(void)
1299 unsigned char pixels[32][32][4];
1300 for (y = 0;y < 32;y++)
1302 dy = (y - 15.5f) * (1.0f / 16.0f);
1303 for (x = 0;x < 32;x++)
1305 dx = (x - 15.5f) * (1.0f / 16.0f);
1306 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1307 a = bound(0, a, 255);
1308 pixels[y][x][0] = a;
1309 pixels[y][x][1] = a;
1310 pixels[y][x][2] = a;
1311 pixels[y][x][3] = 255;
1314 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1317 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1319 float dist = sqrt(x*x+y*y+z*z);
1320 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1321 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1322 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1325 static void R_Shadow_MakeTextures(void)
1328 float intensity, dist;
1330 R_FreeTexturePool(&r_shadow_texturepool);
1331 r_shadow_texturepool = R_AllocTexturePool();
1332 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1333 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1334 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1335 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1336 for (x = 0;x <= ATTENTABLESIZE;x++)
1338 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1339 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1340 r_shadow_attentable[x] = bound(0, intensity, 1);
1342 // 1D gradient texture
1343 for (x = 0;x < ATTEN1DSIZE;x++)
1344 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1345 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);
1346 // 2D circle texture
1347 for (y = 0;y < ATTEN2DSIZE;y++)
1348 for (x = 0;x < ATTEN2DSIZE;x++)
1349 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);
1350 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);
1351 // 3D sphere texture
1352 if (r_shadow_texture3d.integer && gl_texture3d)
1354 for (z = 0;z < ATTEN3DSIZE;z++)
1355 for (y = 0;y < ATTEN3DSIZE;y++)
1356 for (x = 0;x < ATTEN3DSIZE;x++)
1357 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));
1358 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);
1361 r_shadow_attenuation3dtexture = NULL;
1364 R_Shadow_MakeTextures_MakeCorona();
1366 // Editor light sprites
1367 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1368 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1369 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1370 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1371 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1372 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1375 void R_Shadow_ValidateCvars(void)
1377 if (r_shadow_texture3d.integer && !gl_texture3d)
1378 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1379 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1380 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1381 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1382 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1385 void R_Shadow_RenderMode_Begin(void)
1389 R_Shadow_ValidateCvars();
1391 if (!r_shadow_attenuation2dtexture
1392 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1393 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1394 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1395 R_Shadow_MakeTextures();
1398 R_Mesh_ColorPointer(NULL, 0, 0);
1399 R_Mesh_ResetTextureState();
1400 GL_BlendFunc(GL_ONE, GL_ZERO);
1401 GL_DepthRange(0, 1);
1402 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1404 GL_DepthMask(false);
1405 GL_Color(0, 0, 0, 1);
1406 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1408 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1410 if (gl_ext_separatestencil.integer)
1412 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1413 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1415 else if (gl_ext_stenciltwoside.integer)
1417 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1418 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1422 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1423 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1426 if (r_glsl.integer && gl_support_fragment_shader)
1427 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1428 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1429 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1431 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1434 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1435 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1436 r_shadow_drawbuffer = drawbuffer;
1437 r_shadow_readbuffer = readbuffer;
1440 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1442 rsurface.rtlight = rtlight;
1445 void R_Shadow_RenderMode_Reset(void)
1448 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1450 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1452 if (gl_support_ext_framebuffer_object)
1454 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1456 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1457 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1458 R_SetViewport(&r_refdef.view.viewport);
1459 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1460 R_Mesh_ColorPointer(NULL, 0, 0);
1461 R_Mesh_ResetTextureState();
1462 GL_DepthRange(0, 1);
1464 GL_DepthMask(false);
1465 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1466 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1467 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1468 qglStencilMask(~0);CHECKGLERROR
1469 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1470 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1471 GL_CullFace(r_refdef.view.cullface_back);
1472 GL_Color(1, 1, 1, 1);
1473 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1474 GL_BlendFunc(GL_ONE, GL_ZERO);
1475 R_SetupGenericShader(false);
1476 r_shadow_usingshadowmaprect = false;
1477 r_shadow_usingshadowmapcube = false;
1478 r_shadow_usingshadowmap2d = false;
1482 void R_Shadow_ClearStencil(void)
1485 GL_Clear(GL_STENCIL_BUFFER_BIT);
1486 r_refdef.stats.lights_clears++;
1489 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1491 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1492 if (r_shadow_rendermode == mode)
1495 R_Shadow_RenderMode_Reset();
1496 GL_ColorMask(0, 0, 0, 0);
1497 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1498 R_SetupDepthOrShadowShader();
1499 qglDepthFunc(GL_LESS);CHECKGLERROR
1500 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1501 r_shadow_rendermode = mode;
1506 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1507 GL_CullFace(GL_NONE);
1508 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1509 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1511 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1512 GL_CullFace(GL_NONE);
1513 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1514 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1516 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1517 GL_CullFace(GL_NONE);
1518 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1519 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1520 qglStencilMask(~0);CHECKGLERROR
1521 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1522 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1523 qglStencilMask(~0);CHECKGLERROR
1524 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1526 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1527 GL_CullFace(GL_NONE);
1528 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1529 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1530 qglStencilMask(~0);CHECKGLERROR
1531 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1532 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1533 qglStencilMask(~0);CHECKGLERROR
1534 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1539 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1544 float nearclip, farclip, bias;
1545 r_viewport_t viewport;
1547 maxsize = r_shadow_shadowmapmaxsize;
1548 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1550 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1551 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1552 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1553 if (r_shadow_shadowmode == 1)
1555 // complex unrolled cube approach (more flexible)
1556 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1557 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1558 if (!r_shadow_shadowmap2dtexture)
1561 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1562 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapsampler);
1563 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1564 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1565 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1569 R_Shadow_RenderMode_Reset();
1570 if (r_shadow_shadowmap2dtexture)
1572 // render depth into the fbo, do not render color at all
1573 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1574 qglDrawBuffer(GL_NONE);CHECKGLERROR
1575 qglReadBuffer(GL_NONE);CHECKGLERROR
1576 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1577 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1579 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1580 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1582 R_SetupDepthOrShadowShader();
1586 R_SetupShowDepthShader();
1587 qglClearColor(1,1,1,1);CHECKGLERROR
1589 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1590 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1591 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1592 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? 2*size * r_shadow_shadowmap_texturescale[0] : 0.5f * (size - r_shadow_shadowmapborder);
1593 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 3*size * r_shadow_shadowmap_texturescale[1] : size;
1594 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1596 else if (r_shadow_shadowmode == 2)
1598 // complex unrolled cube approach (more flexible)
1599 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1600 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1601 if (!r_shadow_shadowmaprectangletexture)
1604 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapsampler);
1605 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1606 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1607 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1611 R_Shadow_RenderMode_Reset();
1612 if (r_shadow_shadowmaprectangletexture)
1614 // render depth into the fbo, do not render color at all
1615 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1616 qglDrawBuffer(GL_NONE);CHECKGLERROR
1617 qglReadBuffer(GL_NONE);CHECKGLERROR
1618 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1619 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1621 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1622 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1624 R_SetupDepthOrShadowShader();
1628 R_SetupShowDepthShader();
1629 qglClearColor(1,1,1,1);CHECKGLERROR
1631 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1632 r_shadow_shadowmap_texturescale[0] = 1.0f;
1633 r_shadow_shadowmap_texturescale[1] = 1.0f;
1634 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? 2*size : 0.5f * (size - r_shadow_shadowmapborder);
1635 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 3*size : size;
1636 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1638 else if (r_shadow_shadowmode == 3)
1640 // simple cube approach
1641 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1644 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapsampler);
1645 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1646 for (i = 0;i < 6;i++)
1648 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1649 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
1654 R_Shadow_RenderMode_Reset();
1655 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1657 // render depth into the fbo, do not render color at all
1658 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1659 qglDrawBuffer(GL_NONE);CHECKGLERROR
1660 qglReadBuffer(GL_NONE);CHECKGLERROR
1661 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1662 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1664 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1665 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1667 R_SetupDepthOrShadowShader();
1671 R_SetupShowDepthShader();
1672 qglClearColor(1,1,1,1);CHECKGLERROR
1674 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1675 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1676 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1677 r_shadow_shadowmap_parameters[0] = 1.0f;
1678 r_shadow_shadowmap_parameters[1] = 1.0f;
1679 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1681 r_shadow_shadowmap_texturescale[2] = 1.0f / r_shadow_shadowmap_texturescale[0];
1682 r_shadow_shadowmap_texturescale[3] = 1.0f / r_shadow_shadowmap_texturescale[1];
1684 R_SetViewport(&viewport);
1685 GL_PolygonOffset(0, 0);
1686 GL_CullFace(GL_NONE); // quake is backwards
1687 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1690 qglClearDepth(1);CHECKGLERROR
1693 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1697 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1700 R_Shadow_RenderMode_Reset();
1701 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1704 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1708 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1709 // only draw light where this geometry was already rendered AND the
1710 // stencil is 128 (values other than this mean shadow)
1711 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1713 r_shadow_rendermode = r_shadow_lightingrendermode;
1714 // do global setup needed for the chosen lighting mode
1715 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1717 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1718 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1722 if (r_shadow_shadowmode == 1)
1724 r_shadow_usingshadowmap2d = true;
1725 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1728 else if (r_shadow_shadowmode == 2)
1730 r_shadow_usingshadowmaprect = true;
1731 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1734 else if (r_shadow_shadowmode == 3)
1736 r_shadow_usingshadowmapcube = true;
1737 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1741 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1743 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]));
1748 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1749 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1750 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1754 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1757 R_Shadow_RenderMode_Reset();
1758 GL_BlendFunc(GL_ONE, GL_ONE);
1759 GL_DepthRange(0, 1);
1760 GL_DepthTest(r_showshadowvolumes.integer < 2);
1761 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1762 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1763 GL_CullFace(GL_NONE);
1764 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1767 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1770 R_Shadow_RenderMode_Reset();
1771 GL_BlendFunc(GL_ONE, GL_ONE);
1772 GL_DepthRange(0, 1);
1773 GL_DepthTest(r_showlighting.integer < 2);
1774 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1777 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1781 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1782 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1784 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1787 void R_Shadow_RenderMode_End(void)
1790 R_Shadow_RenderMode_Reset();
1791 R_Shadow_RenderMode_ActiveLight(NULL);
1793 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1794 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1797 int bboxedges[12][2] =
1816 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1818 int i, ix1, iy1, ix2, iy2;
1819 float x1, y1, x2, y2;
1821 float vertex[20][3];
1830 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1831 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1832 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1833 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1835 if (!r_shadow_scissor.integer)
1838 // if view is inside the light box, just say yes it's visible
1839 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1842 x1 = y1 = x2 = y2 = 0;
1844 // transform all corners that are infront of the nearclip plane
1845 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1846 plane4f[3] = r_refdef.view.frustum[4].dist;
1848 for (i = 0;i < 8;i++)
1850 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1851 dist[i] = DotProduct4(corner[i], plane4f);
1852 sign[i] = dist[i] > 0;
1855 VectorCopy(corner[i], vertex[numvertices]);
1859 // if some points are behind the nearclip, add clipped edge points to make
1860 // sure that the scissor boundary is complete
1861 if (numvertices > 0 && numvertices < 8)
1863 // add clipped edge points
1864 for (i = 0;i < 12;i++)
1866 j = bboxedges[i][0];
1867 k = bboxedges[i][1];
1868 if (sign[j] != sign[k])
1870 f = dist[j] / (dist[j] - dist[k]);
1871 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1877 // if we have no points to check, the light is behind the view plane
1881 // if we have some points to transform, check what screen area is covered
1882 x1 = y1 = x2 = y2 = 0;
1884 //Con_Printf("%i vertices to transform...\n", numvertices);
1885 for (i = 0;i < numvertices;i++)
1887 VectorCopy(vertex[i], v);
1888 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1889 //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]);
1892 if (x1 > v2[0]) x1 = v2[0];
1893 if (x2 < v2[0]) x2 = v2[0];
1894 if (y1 > v2[1]) y1 = v2[1];
1895 if (y2 < v2[1]) y2 = v2[1];
1904 // now convert the scissor rectangle to integer screen coordinates
1905 ix1 = (int)(x1 - 1.0f);
1906 iy1 = vid.height - (int)(y2 - 1.0f);
1907 ix2 = (int)(x2 + 1.0f);
1908 iy2 = vid.height - (int)(y1 + 1.0f);
1909 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1911 // clamp it to the screen
1912 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1913 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1914 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1915 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1917 // if it is inside out, it's not visible
1918 if (ix2 <= ix1 || iy2 <= iy1)
1921 // the light area is visible, set up the scissor rectangle
1922 r_shadow_lightscissor[0] = ix1;
1923 r_shadow_lightscissor[1] = iy1;
1924 r_shadow_lightscissor[2] = ix2 - ix1;
1925 r_shadow_lightscissor[3] = iy2 - iy1;
1927 r_refdef.stats.lights_scissored++;
1931 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1933 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1934 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1935 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1936 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1937 if (r_textureunits.integer >= 3)
1939 if (VectorLength2(diffusecolor) > 0)
1941 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1943 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1944 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1945 if ((dot = DotProduct(n, v)) < 0)
1947 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1948 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1951 VectorCopy(ambientcolor, color4f);
1952 if (r_refdef.fogenabled)
1955 f = FogPoint_Model(vertex3f);
1956 VectorScale(color4f, f, color4f);
1963 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1965 VectorCopy(ambientcolor, color4f);
1966 if (r_refdef.fogenabled)
1969 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1970 f = FogPoint_Model(vertex3f);
1971 VectorScale(color4f, f, color4f);
1977 else if (r_textureunits.integer >= 2)
1979 if (VectorLength2(diffusecolor) > 0)
1981 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1983 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1984 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1986 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1987 if ((dot = DotProduct(n, v)) < 0)
1989 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1990 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1991 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1992 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1996 color4f[0] = ambientcolor[0] * distintensity;
1997 color4f[1] = ambientcolor[1] * distintensity;
1998 color4f[2] = ambientcolor[2] * distintensity;
2000 if (r_refdef.fogenabled)
2003 f = FogPoint_Model(vertex3f);
2004 VectorScale(color4f, f, color4f);
2008 VectorClear(color4f);
2014 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2016 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2017 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2019 color4f[0] = ambientcolor[0] * distintensity;
2020 color4f[1] = ambientcolor[1] * distintensity;
2021 color4f[2] = ambientcolor[2] * distintensity;
2022 if (r_refdef.fogenabled)
2025 f = FogPoint_Model(vertex3f);
2026 VectorScale(color4f, f, color4f);
2030 VectorClear(color4f);
2037 if (VectorLength2(diffusecolor) > 0)
2039 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2041 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2042 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2044 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2045 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2046 if ((dot = DotProduct(n, v)) < 0)
2048 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2049 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2050 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2051 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2055 color4f[0] = ambientcolor[0] * distintensity;
2056 color4f[1] = ambientcolor[1] * distintensity;
2057 color4f[2] = ambientcolor[2] * distintensity;
2059 if (r_refdef.fogenabled)
2062 f = FogPoint_Model(vertex3f);
2063 VectorScale(color4f, f, color4f);
2067 VectorClear(color4f);
2073 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2075 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2076 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2078 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2079 color4f[0] = ambientcolor[0] * distintensity;
2080 color4f[1] = ambientcolor[1] * distintensity;
2081 color4f[2] = ambientcolor[2] * distintensity;
2082 if (r_refdef.fogenabled)
2085 f = FogPoint_Model(vertex3f);
2086 VectorScale(color4f, f, color4f);
2090 VectorClear(color4f);
2097 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2099 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2102 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2103 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2104 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2105 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2106 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2108 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2110 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2111 // the cubemap normalizes this for us
2112 out3f[0] = DotProduct(svector3f, lightdir);
2113 out3f[1] = DotProduct(tvector3f, lightdir);
2114 out3f[2] = DotProduct(normal3f, lightdir);
2118 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2121 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2122 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2123 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2124 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2125 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2126 float lightdir[3], eyedir[3], halfdir[3];
2127 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2129 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2130 VectorNormalize(lightdir);
2131 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2132 VectorNormalize(eyedir);
2133 VectorAdd(lightdir, eyedir, halfdir);
2134 // the cubemap normalizes this for us
2135 out3f[0] = DotProduct(svector3f, halfdir);
2136 out3f[1] = DotProduct(tvector3f, halfdir);
2137 out3f[2] = DotProduct(normal3f, halfdir);
2141 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)
2143 // used to display how many times a surface is lit for level design purposes
2144 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2147 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)
2149 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2150 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2151 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2152 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2154 R_Mesh_ColorPointer(NULL, 0, 0);
2155 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2156 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2157 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2158 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2159 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2160 if (rsurface.texture->backgroundcurrentskinframe)
2162 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2163 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2164 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2165 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2167 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2168 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2169 if(rsurface.texture->colormapping)
2171 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2172 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2174 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2175 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2176 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2177 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2178 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2179 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2181 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2183 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2184 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2186 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2190 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)
2192 // shared final code for all the dot3 layers
2194 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2195 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2197 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2198 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2202 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)
2205 // colorscale accounts for how much we multiply the brightness
2208 // mult is how many times the final pass of the lighting will be
2209 // performed to get more brightness than otherwise possible.
2211 // Limit mult to 64 for sanity sake.
2213 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2215 // 3 3D combine path (Geforce3, Radeon 8500)
2216 memset(&m, 0, sizeof(m));
2217 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2218 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2219 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2220 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2221 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2222 m.tex[1] = R_GetTexture(basetexture);
2223 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2224 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2225 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2226 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2227 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2228 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2229 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2230 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2231 m.texmatrix[2] = rsurface.entitytolight;
2232 GL_BlendFunc(GL_ONE, GL_ONE);
2234 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2236 // 2 3D combine path (Geforce3, original Radeon)
2237 memset(&m, 0, sizeof(m));
2238 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2239 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2240 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2241 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2242 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2243 m.tex[1] = R_GetTexture(basetexture);
2244 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2245 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2246 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2247 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2248 GL_BlendFunc(GL_ONE, GL_ONE);
2250 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2252 // 4 2D combine path (Geforce3, Radeon 8500)
2253 memset(&m, 0, sizeof(m));
2254 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2255 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2256 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2258 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2259 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2260 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2261 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2262 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2263 m.texmatrix[1] = rsurface.entitytoattenuationz;
2264 m.tex[2] = R_GetTexture(basetexture);
2265 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2266 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2267 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2268 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2269 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2271 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2272 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2273 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2274 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2275 m.texmatrix[3] = rsurface.entitytolight;
2277 GL_BlendFunc(GL_ONE, GL_ONE);
2279 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2281 // 3 2D combine path (Geforce3, original Radeon)
2282 memset(&m, 0, sizeof(m));
2283 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2284 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2285 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2286 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2287 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2288 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2289 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2290 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2291 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2292 m.texmatrix[1] = rsurface.entitytoattenuationz;
2293 m.tex[2] = R_GetTexture(basetexture);
2294 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2295 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2296 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2297 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2298 GL_BlendFunc(GL_ONE, GL_ONE);
2302 // 2/2/2 2D combine path (any dot3 card)
2303 memset(&m, 0, sizeof(m));
2304 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2305 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2306 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2307 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2308 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2309 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2310 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2311 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2312 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2313 m.texmatrix[1] = rsurface.entitytoattenuationz;
2314 R_Mesh_TextureState(&m);
2315 GL_ColorMask(0,0,0,1);
2316 GL_BlendFunc(GL_ONE, GL_ZERO);
2317 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2320 memset(&m, 0, sizeof(m));
2321 m.tex[0] = R_GetTexture(basetexture);
2322 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2323 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2324 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2325 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2326 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2328 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2329 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2330 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2331 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2332 m.texmatrix[1] = rsurface.entitytolight;
2334 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2336 // this final code is shared
2337 R_Mesh_TextureState(&m);
2338 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);
2341 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)
2344 // colorscale accounts for how much we multiply the brightness
2347 // mult is how many times the final pass of the lighting will be
2348 // performed to get more brightness than otherwise possible.
2350 // Limit mult to 64 for sanity sake.
2352 // generate normalization cubemap texcoords
2353 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2354 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2356 // 3/2 3D combine path (Geforce3, Radeon 8500)
2357 memset(&m, 0, sizeof(m));
2358 m.tex[0] = R_GetTexture(normalmaptexture);
2359 m.texcombinergb[0] = GL_REPLACE;
2360 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2361 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2362 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2363 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2364 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2365 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2366 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2367 m.pointer_texcoord_bufferobject[1] = 0;
2368 m.pointer_texcoord_bufferoffset[1] = 0;
2369 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2370 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2371 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2372 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2373 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2374 R_Mesh_TextureState(&m);
2375 GL_ColorMask(0,0,0,1);
2376 GL_BlendFunc(GL_ONE, GL_ZERO);
2377 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2380 memset(&m, 0, sizeof(m));
2381 m.tex[0] = R_GetTexture(basetexture);
2382 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2383 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2384 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2385 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2386 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2388 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2389 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2390 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2391 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2392 m.texmatrix[1] = rsurface.entitytolight;
2394 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2396 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2398 // 1/2/2 3D combine path (original Radeon)
2399 memset(&m, 0, sizeof(m));
2400 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2401 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2402 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2403 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2404 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2405 R_Mesh_TextureState(&m);
2406 GL_ColorMask(0,0,0,1);
2407 GL_BlendFunc(GL_ONE, GL_ZERO);
2408 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2411 memset(&m, 0, sizeof(m));
2412 m.tex[0] = R_GetTexture(normalmaptexture);
2413 m.texcombinergb[0] = GL_REPLACE;
2414 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2415 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2416 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2417 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2418 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2419 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2420 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2421 m.pointer_texcoord_bufferobject[1] = 0;
2422 m.pointer_texcoord_bufferoffset[1] = 0;
2423 R_Mesh_TextureState(&m);
2424 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2425 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2428 memset(&m, 0, sizeof(m));
2429 m.tex[0] = R_GetTexture(basetexture);
2430 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2431 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2432 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2433 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2434 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2436 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2437 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2438 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2439 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2440 m.texmatrix[1] = rsurface.entitytolight;
2442 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2444 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2446 // 2/2 3D combine path (original Radeon)
2447 memset(&m, 0, sizeof(m));
2448 m.tex[0] = R_GetTexture(normalmaptexture);
2449 m.texcombinergb[0] = GL_REPLACE;
2450 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2451 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2452 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2453 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2454 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2455 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2456 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2457 m.pointer_texcoord_bufferobject[1] = 0;
2458 m.pointer_texcoord_bufferoffset[1] = 0;
2459 R_Mesh_TextureState(&m);
2460 GL_ColorMask(0,0,0,1);
2461 GL_BlendFunc(GL_ONE, GL_ZERO);
2462 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2465 memset(&m, 0, sizeof(m));
2466 m.tex[0] = R_GetTexture(basetexture);
2467 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2468 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2469 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2470 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2471 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2472 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2473 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2474 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2475 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2476 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2478 else if (r_textureunits.integer >= 4)
2480 // 4/2 2D combine path (Geforce3, Radeon 8500)
2481 memset(&m, 0, sizeof(m));
2482 m.tex[0] = R_GetTexture(normalmaptexture);
2483 m.texcombinergb[0] = GL_REPLACE;
2484 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2485 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2486 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2487 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2488 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2489 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2490 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2491 m.pointer_texcoord_bufferobject[1] = 0;
2492 m.pointer_texcoord_bufferoffset[1] = 0;
2493 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2494 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2495 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2496 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2497 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2498 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2499 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2500 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2501 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2502 m.texmatrix[3] = rsurface.entitytoattenuationz;
2503 R_Mesh_TextureState(&m);
2504 GL_ColorMask(0,0,0,1);
2505 GL_BlendFunc(GL_ONE, GL_ZERO);
2506 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2509 memset(&m, 0, sizeof(m));
2510 m.tex[0] = R_GetTexture(basetexture);
2511 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2512 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2513 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2514 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2515 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2517 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2518 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2519 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2520 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2521 m.texmatrix[1] = rsurface.entitytolight;
2523 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2527 // 2/2/2 2D combine path (any dot3 card)
2528 memset(&m, 0, sizeof(m));
2529 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2530 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2531 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2532 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2533 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2534 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2535 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2536 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2537 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2538 m.texmatrix[1] = rsurface.entitytoattenuationz;
2539 R_Mesh_TextureState(&m);
2540 GL_ColorMask(0,0,0,1);
2541 GL_BlendFunc(GL_ONE, GL_ZERO);
2542 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2545 memset(&m, 0, sizeof(m));
2546 m.tex[0] = R_GetTexture(normalmaptexture);
2547 m.texcombinergb[0] = GL_REPLACE;
2548 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2549 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2550 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2551 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2552 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2553 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2554 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2555 m.pointer_texcoord_bufferobject[1] = 0;
2556 m.pointer_texcoord_bufferoffset[1] = 0;
2557 R_Mesh_TextureState(&m);
2558 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2559 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2562 memset(&m, 0, sizeof(m));
2563 m.tex[0] = R_GetTexture(basetexture);
2564 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2565 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2566 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2567 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2568 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2570 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2571 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2572 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2573 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2574 m.texmatrix[1] = rsurface.entitytolight;
2576 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2578 // this final code is shared
2579 R_Mesh_TextureState(&m);
2580 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);
2583 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)
2585 float glossexponent;
2587 // FIXME: detect blendsquare!
2588 //if (!gl_support_blendsquare)
2591 // generate normalization cubemap texcoords
2592 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2593 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2595 // 2/0/0/1/2 3D combine blendsquare path
2596 memset(&m, 0, sizeof(m));
2597 m.tex[0] = R_GetTexture(normalmaptexture);
2598 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2599 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2600 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2601 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2602 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2603 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2604 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2605 m.pointer_texcoord_bufferobject[1] = 0;
2606 m.pointer_texcoord_bufferoffset[1] = 0;
2607 R_Mesh_TextureState(&m);
2608 GL_ColorMask(0,0,0,1);
2609 // this squares the result
2610 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2611 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2613 // second and third pass
2614 R_Mesh_ResetTextureState();
2615 // square alpha in framebuffer a few times to make it shiny
2616 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2617 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2618 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2621 memset(&m, 0, sizeof(m));
2622 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2623 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2624 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2625 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2626 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2627 R_Mesh_TextureState(&m);
2628 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2629 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2632 memset(&m, 0, sizeof(m));
2633 m.tex[0] = R_GetTexture(glosstexture);
2634 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2635 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2636 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2637 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2638 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2640 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2641 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2642 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2643 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2644 m.texmatrix[1] = rsurface.entitytolight;
2646 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2648 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2650 // 2/0/0/2 3D combine blendsquare path
2651 memset(&m, 0, sizeof(m));
2652 m.tex[0] = R_GetTexture(normalmaptexture);
2653 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2654 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2655 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2656 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2657 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2658 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2659 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2660 m.pointer_texcoord_bufferobject[1] = 0;
2661 m.pointer_texcoord_bufferoffset[1] = 0;
2662 R_Mesh_TextureState(&m);
2663 GL_ColorMask(0,0,0,1);
2664 // this squares the result
2665 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2666 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2668 // second and third pass
2669 R_Mesh_ResetTextureState();
2670 // square alpha in framebuffer a few times to make it shiny
2671 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2672 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2673 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2676 memset(&m, 0, sizeof(m));
2677 m.tex[0] = R_GetTexture(glosstexture);
2678 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2679 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2680 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2681 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2682 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2683 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2684 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2685 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2686 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2687 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2691 // 2/0/0/2/2 2D combine blendsquare path
2692 memset(&m, 0, sizeof(m));
2693 m.tex[0] = R_GetTexture(normalmaptexture);
2694 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2695 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2696 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2697 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2698 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2699 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2700 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2701 m.pointer_texcoord_bufferobject[1] = 0;
2702 m.pointer_texcoord_bufferoffset[1] = 0;
2703 R_Mesh_TextureState(&m);
2704 GL_ColorMask(0,0,0,1);
2705 // this squares the result
2706 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2707 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2709 // second and third pass
2710 R_Mesh_ResetTextureState();
2711 // square alpha in framebuffer a few times to make it shiny
2712 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2713 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2714 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2717 memset(&m, 0, sizeof(m));
2718 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2719 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2720 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2721 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2722 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2723 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2724 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2725 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2726 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2727 m.texmatrix[1] = rsurface.entitytoattenuationz;
2728 R_Mesh_TextureState(&m);
2729 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2730 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2733 memset(&m, 0, sizeof(m));
2734 m.tex[0] = R_GetTexture(glosstexture);
2735 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2736 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2737 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2738 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2739 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2741 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2742 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2743 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2744 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2745 m.texmatrix[1] = rsurface.entitytolight;
2747 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2749 // this final code is shared
2750 R_Mesh_TextureState(&m);
2751 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);
2754 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)
2756 // ARB path (any Geforce, any Radeon)
2757 qboolean doambient = ambientscale > 0;
2758 qboolean dodiffuse = diffusescale > 0;
2759 qboolean dospecular = specularscale > 0;
2760 if (!doambient && !dodiffuse && !dospecular)
2762 R_Mesh_ColorPointer(NULL, 0, 0);
2764 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2766 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2770 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2772 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2777 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2779 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2782 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2785 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2792 int newnumtriangles;
2796 int maxtriangles = 4096;
2797 int newelements[4096*3];
2798 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2799 for (renders = 0;renders < 64;renders++)
2804 newnumtriangles = 0;
2806 // due to low fillrate on the cards this vertex lighting path is
2807 // designed for, we manually cull all triangles that do not
2808 // contain a lit vertex
2809 // this builds batches of triangles from multiple surfaces and
2810 // renders them at once
2811 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2813 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2815 if (newnumtriangles)
2817 newfirstvertex = min(newfirstvertex, e[0]);
2818 newlastvertex = max(newlastvertex, e[0]);
2822 newfirstvertex = e[0];
2823 newlastvertex = e[0];
2825 newfirstvertex = min(newfirstvertex, e[1]);
2826 newlastvertex = max(newlastvertex, e[1]);
2827 newfirstvertex = min(newfirstvertex, e[2]);
2828 newlastvertex = max(newlastvertex, e[2]);
2834 if (newnumtriangles >= maxtriangles)
2836 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2837 newnumtriangles = 0;
2843 if (newnumtriangles >= 1)
2845 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2848 // if we couldn't find any lit triangles, exit early
2851 // now reduce the intensity for the next overbright pass
2852 // we have to clamp to 0 here incase the drivers have improper
2853 // handling of negative colors
2854 // (some old drivers even have improper handling of >1 color)
2856 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2858 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2860 c[0] = max(0, c[0] - 1);
2861 c[1] = max(0, c[1] - 1);
2862 c[2] = max(0, c[2] - 1);
2874 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)
2876 // OpenGL 1.1 path (anything)
2877 float ambientcolorbase[3], diffusecolorbase[3];
2878 float ambientcolorpants[3], diffusecolorpants[3];
2879 float ambientcolorshirt[3], diffusecolorshirt[3];
2881 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2882 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2883 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2884 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2885 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2886 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2887 memset(&m, 0, sizeof(m));
2888 m.tex[0] = R_GetTexture(basetexture);
2889 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2890 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2891 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2892 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2893 if (r_textureunits.integer >= 2)
2896 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2897 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2898 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2899 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2900 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2901 if (r_textureunits.integer >= 3)
2903 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2904 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2905 m.texmatrix[2] = rsurface.entitytoattenuationz;
2906 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2907 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2908 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2911 R_Mesh_TextureState(&m);
2912 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2913 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2916 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2917 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2921 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2922 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2926 extern cvar_t gl_lightmaps;
2927 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)
2929 float ambientscale, diffusescale, specularscale;
2930 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2932 // calculate colors to render this texture with
2933 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2934 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2935 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2936 ambientscale = rsurface.rtlight->ambientscale;
2937 diffusescale = rsurface.rtlight->diffusescale;
2938 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2939 if (!r_shadow_usenormalmap.integer)
2941 ambientscale += 1.0f * diffusescale;
2945 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2947 RSurf_SetupDepthAndCulling();
2948 nmap = rsurface.texture->currentskinframe->nmap;
2949 if (gl_lightmaps.integer)
2950 nmap = r_texture_blanknormalmap;
2951 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2953 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2954 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2957 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2958 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2959 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2962 VectorClear(lightcolorpants);
2965 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2966 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2967 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2970 VectorClear(lightcolorshirt);
2971 switch (r_shadow_rendermode)
2973 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2974 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2975 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);
2977 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2978 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);
2980 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2981 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);
2983 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2984 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);
2987 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2993 switch (r_shadow_rendermode)
2995 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2996 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2997 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);
2999 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3000 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);
3002 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3003 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);
3005 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3006 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);
3009 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3015 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)
3017 matrix4x4_t tempmatrix = *matrix;
3018 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3020 // if this light has been compiled before, free the associated data
3021 R_RTLight_Uncompile(rtlight);
3023 // clear it completely to avoid any lingering data
3024 memset(rtlight, 0, sizeof(*rtlight));
3026 // copy the properties
3027 rtlight->matrix_lighttoworld = tempmatrix;
3028 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3029 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3030 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3031 VectorCopy(color, rtlight->color);
3032 rtlight->cubemapname[0] = 0;
3033 if (cubemapname && cubemapname[0])
3034 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3035 rtlight->shadow = shadow;
3036 rtlight->corona = corona;
3037 rtlight->style = style;
3038 rtlight->isstatic = isstatic;
3039 rtlight->coronasizescale = coronasizescale;
3040 rtlight->ambientscale = ambientscale;
3041 rtlight->diffusescale = diffusescale;
3042 rtlight->specularscale = specularscale;
3043 rtlight->flags = flags;
3045 // compute derived data
3046 //rtlight->cullradius = rtlight->radius;
3047 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3048 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3049 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3050 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3051 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3052 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3053 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3056 // compiles rtlight geometry
3057 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3058 void R_RTLight_Compile(rtlight_t *rtlight)
3061 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3062 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3063 entity_render_t *ent = r_refdef.scene.worldentity;
3064 dp_model_t *model = r_refdef.scene.worldmodel;
3065 unsigned char *data;
3068 // compile the light
3069 rtlight->compiled = true;
3070 rtlight->static_numleafs = 0;
3071 rtlight->static_numleafpvsbytes = 0;
3072 rtlight->static_leaflist = NULL;
3073 rtlight->static_leafpvs = NULL;
3074 rtlight->static_numsurfaces = 0;
3075 rtlight->static_surfacelist = NULL;
3076 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3077 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3078 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3079 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3080 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3081 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3083 if (model && model->GetLightInfo)
3085 // this variable must be set for the CompileShadowVolume code
3086 r_shadow_compilingrtlight = rtlight;
3087 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);
3088 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);
3089 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3090 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3091 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3092 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3093 rtlight->static_numsurfaces = numsurfaces;
3094 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3095 rtlight->static_numleafs = numleafs;
3096 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3097 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3098 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3099 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3100 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3101 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3102 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3103 if (rtlight->static_numsurfaces)
3104 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3105 if (rtlight->static_numleafs)
3106 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3107 if (rtlight->static_numleafpvsbytes)
3108 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3109 if (rtlight->static_numshadowtrispvsbytes)
3110 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3111 if (rtlight->static_numlighttrispvsbytes)
3112 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3113 if (model->CompileShadowVolume && rtlight->shadow)
3114 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3115 // now we're done compiling the rtlight
3116 r_shadow_compilingrtlight = NULL;
3120 // use smallest available cullradius - box radius or light radius
3121 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3122 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3124 shadowzpasstris = 0;
3125 if (rtlight->static_meshchain_shadow_zpass)
3126 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3127 shadowzpasstris += mesh->numtriangles;
3129 shadowzfailtris = 0;
3130 if (rtlight->static_meshchain_shadow_zfail)
3131 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3132 shadowzfailtris += mesh->numtriangles;
3135 if (rtlight->static_numlighttrispvsbytes)
3136 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3137 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3141 if (rtlight->static_numlighttrispvsbytes)
3142 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3143 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3146 if (developer.integer >= 10)
3147 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);
3150 void R_RTLight_Uncompile(rtlight_t *rtlight)
3152 if (rtlight->compiled)
3154 if (rtlight->static_meshchain_shadow_zpass)
3155 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3156 rtlight->static_meshchain_shadow_zpass = NULL;
3157 if (rtlight->static_meshchain_shadow_zfail)
3158 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3159 rtlight->static_meshchain_shadow_zfail = NULL;
3160 // these allocations are grouped
3161 if (rtlight->static_surfacelist)
3162 Mem_Free(rtlight->static_surfacelist);
3163 rtlight->static_numleafs = 0;
3164 rtlight->static_numleafpvsbytes = 0;
3165 rtlight->static_leaflist = NULL;
3166 rtlight->static_leafpvs = NULL;
3167 rtlight->static_numsurfaces = 0;
3168 rtlight->static_surfacelist = NULL;
3169 rtlight->static_numshadowtrispvsbytes = 0;
3170 rtlight->static_shadowtrispvs = NULL;
3171 rtlight->static_numlighttrispvsbytes = 0;
3172 rtlight->static_lighttrispvs = NULL;
3173 rtlight->compiled = false;
3177 void R_Shadow_UncompileWorldLights(void)
3181 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3182 for (lightindex = 0;lightindex < range;lightindex++)
3184 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3187 R_RTLight_Uncompile(&light->rtlight);
3191 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3195 // reset the count of frustum planes
3196 // see rsurface.rtlight_frustumplanes definition for how much this array
3198 rsurface.rtlight_numfrustumplanes = 0;
3200 // haven't implemented a culling path for ortho rendering
3201 if (!r_refdef.view.useperspective)
3203 // check if the light is on screen and copy the 4 planes if it is
3204 for (i = 0;i < 4;i++)
3205 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3208 for (i = 0;i < 4;i++)
3209 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3214 // generate a deformed frustum that includes the light origin, this is
3215 // used to cull shadow casting surfaces that can not possibly cast a
3216 // shadow onto the visible light-receiving surfaces, which can be a
3219 // if the light origin is onscreen the result will be 4 planes exactly
3220 // if the light origin is offscreen on only one axis the result will
3221 // be exactly 5 planes (split-side case)
3222 // if the light origin is offscreen on two axes the result will be
3223 // exactly 4 planes (stretched corner case)
3224 for (i = 0;i < 4;i++)
3226 // quickly reject standard frustum planes that put the light
3227 // origin outside the frustum
3228 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3231 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3233 // if all the standard frustum planes were accepted, the light is onscreen
3234 // otherwise we need to generate some more planes below...
3235 if (rsurface.rtlight_numfrustumplanes < 4)
3237 // at least one of the stock frustum planes failed, so we need to
3238 // create one or two custom planes to enclose the light origin
3239 for (i = 0;i < 4;i++)
3241 // create a plane using the view origin and light origin, and a
3242 // single point from the frustum corner set
3243 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3244 VectorNormalize(plane.normal);
3245 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3246 // see if this plane is backwards and flip it if so
3247 for (j = 0;j < 4;j++)
3248 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3252 VectorNegate(plane.normal, plane.normal);
3254 // flipped plane, test again to see if it is now valid
3255 for (j = 0;j < 4;j++)
3256 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3258 // if the plane is still not valid, then it is dividing the
3259 // frustum and has to be rejected
3263 // we have created a valid plane, compute extra info
3264 PlaneClassify(&plane);
3266 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3268 // if we've found 5 frustum planes then we have constructed a
3269 // proper split-side case and do not need to keep searching for
3270 // planes to enclose the light origin
3271 if (rsurface.rtlight_numfrustumplanes == 5)
3279 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3281 plane = rsurface.rtlight_frustumplanes[i];
3282 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));
3287 // now add the light-space box planes if the light box is rotated, as any
3288 // caster outside the oriented light box is irrelevant (even if it passed
3289 // the worldspace light box, which is axial)
3290 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3292 for (i = 0;i < 6;i++)
3296 v[i >> 1] = (i & 1) ? -1 : 1;
3297 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3298 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3299 plane.dist = VectorNormalizeLength(plane.normal);
3300 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3301 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3307 // add the world-space reduced box planes
3308 for (i = 0;i < 6;i++)
3310 VectorClear(plane.normal);
3311 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3312 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3313 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3322 // reduce all plane distances to tightly fit the rtlight cull box, which
3324 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3325 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3326 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3327 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3328 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3329 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3330 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3331 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3332 oldnum = rsurface.rtlight_numfrustumplanes;
3333 rsurface.rtlight_numfrustumplanes = 0;
3334 for (j = 0;j < oldnum;j++)
3336 // find the nearest point on the box to this plane
3337 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3338 for (i = 1;i < 8;i++)
3340 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3341 if (bestdist > dist)
3344 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);
3345 // if the nearest point is near or behind the plane, we want this
3346 // plane, otherwise the plane is useless as it won't cull anything
3347 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3349 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3350 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3357 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3362 int surfacelistindex;
3363 msurface_t *surface;
3365 RSurf_ActiveWorldEntity();
3366 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3368 if (r_refdef.scene.worldentity->model)
3369 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3370 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3374 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3377 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3378 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3379 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3380 for (;mesh;mesh = mesh->next)
3382 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3383 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3384 GL_LockArrays(0, mesh->numverts);
3385 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3387 // increment stencil if frontface is infront of depthbuffer
3388 GL_CullFace(r_refdef.view.cullface_back);
3389 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3390 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3391 // decrement stencil if backface is infront of depthbuffer
3392 GL_CullFace(r_refdef.view.cullface_front);
3393 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3395 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3397 // decrement stencil if backface is behind depthbuffer
3398 GL_CullFace(r_refdef.view.cullface_front);
3399 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3400 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3401 // increment stencil if frontface is behind depthbuffer
3402 GL_CullFace(r_refdef.view.cullface_back);
3403 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3405 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3406 GL_LockArrays(0, 0);
3410 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3412 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3413 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3415 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3416 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3417 if (CHECKPVSBIT(trispvs, t))
3418 shadowmarklist[numshadowmark++] = t;
3420 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);
3422 else if (numsurfaces)
3423 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3425 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3428 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3430 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3431 vec_t relativeshadowradius;
3432 RSurf_ActiveModelEntity(ent, false, false);
3433 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3434 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3435 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3436 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3437 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3438 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3439 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3440 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3441 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3442 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3444 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3445 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3448 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3450 // set up properties for rendering light onto this entity
3451 RSurf_ActiveModelEntity(ent, true, true);
3452 GL_AlphaTest(false);
3453 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3454 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3455 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3456 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3457 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3458 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3461 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3463 if (!r_refdef.scene.worldmodel->DrawLight)
3466 // set up properties for rendering light onto this entity
3467 RSurf_ActiveWorldEntity();
3468 GL_AlphaTest(false);
3469 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3470 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3471 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3472 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3473 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3474 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3476 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3478 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3481 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3483 dp_model_t *model = ent->model;
3484 if (!model->DrawLight)
3487 R_Shadow_SetupEntityLight(ent);
3489 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3491 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3495 {{ 0, 0, 0}, "px", true, true, true},
3496 {{ 0, 90, 0}, "py", false, true, false},
3497 {{ 0, 180, 0}, "nx", false, false, true},
3498 {{ 0, 270, 0}, "ny", true, false, false},
3499 {{-90, 180, 0}, "pz", false, false, true},
3500 {{ 90, 180, 0}, "nz", false, false, true}
3503 static const double shadowviewmat16[6][4][4] =
3543 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3547 int numleafs, numsurfaces;
3548 int *leaflist, *surfacelist;
3549 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3550 int numlightentities;
3551 int numlightentities_noselfshadow;
3552 int numshadowentities;
3553 int numshadowentities_noselfshadow;
3554 static entity_render_t *lightentities[MAX_EDICTS];
3555 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3556 static entity_render_t *shadowentities[MAX_EDICTS];
3557 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3558 vec3_t nearestpoint;
3560 qboolean castshadows;
3563 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3564 // skip lights that are basically invisible (color 0 0 0)
3565 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3568 // loading is done before visibility checks because loading should happen
3569 // all at once at the start of a level, not when it stalls gameplay.
3570 // (especially important to benchmarks)
3572 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3573 R_RTLight_Compile(rtlight);
3575 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3577 // look up the light style value at this time
3578 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3579 VectorScale(rtlight->color, f, rtlight->currentcolor);
3581 if (rtlight->selected)
3583 f = 2 + sin(realtime * M_PI * 4.0);
3584 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3588 // if lightstyle is currently off, don't draw the light
3589 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3592 // if the light box is offscreen, skip it
3593 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3596 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3597 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3599 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3601 // compiled light, world available and can receive realtime lighting
3602 // retrieve leaf information
3603 numleafs = rtlight->static_numleafs;
3604 leaflist = rtlight->static_leaflist;
3605 leafpvs = rtlight->static_leafpvs;
3606 numsurfaces = rtlight->static_numsurfaces;
3607 surfacelist = rtlight->static_surfacelist;
3608 shadowtrispvs = rtlight->static_shadowtrispvs;
3609 lighttrispvs = rtlight->static_lighttrispvs;
3611 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3613 // dynamic light, world available and can receive realtime lighting
3614 // calculate lit surfaces and leafs
3615 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);
3616 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);
3617 leaflist = r_shadow_buffer_leaflist;
3618 leafpvs = r_shadow_buffer_leafpvs;
3619 surfacelist = r_shadow_buffer_surfacelist;
3620 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3621 lighttrispvs = r_shadow_buffer_lighttrispvs;
3622 // if the reduced leaf bounds are offscreen, skip it
3623 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3634 shadowtrispvs = NULL;
3635 lighttrispvs = NULL;
3637 // check if light is illuminating any visible leafs
3640 for (i = 0;i < numleafs;i++)
3641 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3646 // set up a scissor rectangle for this light
3647 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3650 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3652 // make a list of lit entities and shadow casting entities
3653 numlightentities = 0;
3654 numlightentities_noselfshadow = 0;
3655 numshadowentities = 0;
3656 numshadowentities_noselfshadow = 0;
3657 // add dynamic entities that are lit by the light
3658 if (r_drawentities.integer)
3660 for (i = 0;i < r_refdef.scene.numentities;i++)
3663 entity_render_t *ent = r_refdef.scene.entities[i];
3665 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3667 // skip the object entirely if it is not within the valid
3668 // shadow-casting region (which includes the lit region)
3669 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3671 if (!(model = ent->model))
3673 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3675 // this entity wants to receive light, is visible, and is
3676 // inside the light box
3677 // TODO: check if the surfaces in the model can receive light
3678 // so now check if it's in a leaf seen by the light
3679 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))
3681 if (ent->flags & RENDER_NOSELFSHADOW)
3682 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3684 lightentities[numlightentities++] = ent;
3685 // since it is lit, it probably also casts a shadow...
3686 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3687 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3688 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3690 // note: exterior models without the RENDER_NOSELFSHADOW
3691 // flag still create a RENDER_NOSELFSHADOW shadow but
3692 // are lit normally, this means that they are
3693 // self-shadowing but do not shadow other
3694 // RENDER_NOSELFSHADOW entities such as the gun
3695 // (very weird, but keeps the player shadow off the gun)
3696 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3697 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3699 shadowentities[numshadowentities++] = ent;
3702 else if (ent->flags & RENDER_SHADOW)
3704 // this entity is not receiving light, but may still need to
3706 // TODO: check if the surfaces in the model can cast shadow
3707 // now check if it is in a leaf seen by the light
3708 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))
3710 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3711 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3712 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3714 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3715 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3717 shadowentities[numshadowentities++] = ent;
3723 // return if there's nothing at all to light
3724 if (!numlightentities && !numsurfaces)
3727 // don't let sound skip if going slow
3728 if (r_refdef.scene.extraupdate)
3731 // make this the active rtlight for rendering purposes
3732 R_Shadow_RenderMode_ActiveLight(rtlight);
3733 // count this light in the r_speeds
3734 r_refdef.stats.lights++;
3736 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3738 // optionally draw visible shape of the shadow volumes
3739 // for performance analysis by level designers
3740 R_Shadow_RenderMode_VisibleShadowVolumes();
3742 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3743 for (i = 0;i < numshadowentities;i++)
3744 R_Shadow_DrawEntityShadow(shadowentities[i]);
3745 for (i = 0;i < numshadowentities_noselfshadow;i++)
3746 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3749 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3751 // optionally draw the illuminated areas
3752 // for performance analysis by level designers
3753 R_Shadow_RenderMode_VisibleLighting(false, false);
3755 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3756 for (i = 0;i < numlightentities;i++)
3757 R_Shadow_DrawEntityLight(lightentities[i]);
3758 for (i = 0;i < numlightentities_noselfshadow;i++)
3759 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3762 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3764 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3765 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3766 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3767 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3768 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3769 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3771 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3776 r_shadow_shadowmaplod = 0;
3777 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3778 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3779 r_shadow_shadowmaplod = i;
3781 size = r_shadow_shadowmapvsdct || r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3782 size = bound(1, size, 2048);
3784 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3786 // render shadow casters into 6 sided depth texture
3787 for (side = 0;side < 6;side++)
3789 R_Shadow_RenderMode_ShadowMap(side, true, size);
3791 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3792 for (i = 0;i < numshadowentities;i++)
3793 R_Shadow_DrawEntityShadow(shadowentities[i]);
3796 if (numlightentities_noselfshadow)
3798 // render lighting using the depth texture as shadowmap
3799 // draw lighting in the unmasked areas
3800 R_Shadow_RenderMode_Lighting(false, false, true);
3801 for (i = 0;i < numlightentities_noselfshadow;i++)
3802 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3805 // render shadow casters into 6 sided depth texture
3806 for (side = 0;side < 6;side++)
3808 R_Shadow_RenderMode_ShadowMap(side, false, size);
3809 for (i = 0;i < numshadowentities_noselfshadow;i++)
3810 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3813 // render lighting using the depth texture as shadowmap
3814 // draw lighting in the unmasked areas
3815 R_Shadow_RenderMode_Lighting(false, false, true);
3816 // draw lighting in the unmasked areas
3818 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3819 for (i = 0;i < numlightentities;i++)
3820 R_Shadow_DrawEntityLight(lightentities[i]);
3822 else if (castshadows && gl_stencil)
3824 // draw stencil shadow volumes to mask off pixels that are in shadow
3825 // so that they won't receive lighting
3826 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3827 R_Shadow_ClearStencil();
3829 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3830 for (i = 0;i < numshadowentities;i++)
3831 R_Shadow_DrawEntityShadow(shadowentities[i]);
3832 if (numlightentities_noselfshadow)
3834 // draw lighting in the unmasked areas
3835 R_Shadow_RenderMode_Lighting(true, false, false);
3836 for (i = 0;i < numlightentities_noselfshadow;i++)
3837 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3839 // optionally draw the illuminated areas
3840 // for performance analysis by level designers
3841 if (r_showlighting.integer && r_refdef.view.showdebug)
3843 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3844 for (i = 0;i < numlightentities_noselfshadow;i++)
3845 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3848 for (i = 0;i < numshadowentities_noselfshadow;i++)
3849 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3851 if (numsurfaces + numlightentities)
3853 // draw lighting in the unmasked areas
3854 R_Shadow_RenderMode_Lighting(true, false, false);
3856 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3857 for (i = 0;i < numlightentities;i++)
3858 R_Shadow_DrawEntityLight(lightentities[i]);
3863 if (numsurfaces + numlightentities)
3865 // draw lighting in the unmasked areas
3866 R_Shadow_RenderMode_Lighting(false, false, false);
3868 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3869 for (i = 0;i < numlightentities;i++)
3870 R_Shadow_DrawEntityLight(lightentities[i]);
3871 for (i = 0;i < numlightentities_noselfshadow;i++)
3872 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3877 void R_Shadow_DrawLightSprites(void);
3878 void R_ShadowVolumeLighting(qboolean visible)
3886 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
3887 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
3888 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3889 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3890 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3891 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3892 R_Shadow_FreeShadowMaps();
3894 if (r_editlights.integer)
3895 R_Shadow_DrawLightSprites();
3897 R_Shadow_RenderMode_Begin();
3899 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3900 if (r_shadow_debuglight.integer >= 0)
3902 lightindex = r_shadow_debuglight.integer;
3903 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3904 if (light && (light->flags & flag))
3905 R_DrawRTLight(&light->rtlight, visible);
3909 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3910 for (lightindex = 0;lightindex < range;lightindex++)
3912 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3913 if (light && (light->flags & flag))
3914 R_DrawRTLight(&light->rtlight, visible);
3917 if (r_refdef.scene.rtdlight)
3918 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3919 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3921 R_Shadow_RenderMode_End();
3924 extern const float r_screenvertex3f[12];
3925 extern void R_SetupView(qboolean allowwaterclippingplane);
3926 extern void R_ResetViewRendering3D(void);
3927 extern void R_ResetViewRendering2D(void);
3928 extern cvar_t r_shadows;
3929 extern cvar_t r_shadows_darken;
3930 extern cvar_t r_shadows_drawafterrtlighting;
3931 extern cvar_t r_shadows_castfrombmodels;
3932 extern cvar_t r_shadows_throwdistance;
3933 extern cvar_t r_shadows_throwdirection;
3934 void R_DrawModelShadows(void)
3937 float relativethrowdistance;
3938 entity_render_t *ent;
3939 vec3_t relativelightorigin;
3940 vec3_t relativelightdirection;
3941 vec3_t relativeshadowmins, relativeshadowmaxs;
3942 vec3_t tmp, shadowdir;
3944 if (!r_drawentities.integer || !gl_stencil)
3948 R_ResetViewRendering3D();
3949 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3950 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3951 R_Shadow_RenderMode_Begin();
3952 R_Shadow_RenderMode_ActiveLight(NULL);
3953 r_shadow_lightscissor[0] = r_refdef.view.x;
3954 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3955 r_shadow_lightscissor[2] = r_refdef.view.width;
3956 r_shadow_lightscissor[3] = r_refdef.view.height;
3957 R_Shadow_RenderMode_StencilShadowVolumes(false);
3960 if (r_shadows.integer == 2)
3962 Math_atov(r_shadows_throwdirection.string, shadowdir);
3963 VectorNormalize(shadowdir);
3966 R_Shadow_ClearStencil();
3968 for (i = 0;i < r_refdef.scene.numentities;i++)
3970 ent = r_refdef.scene.entities[i];
3972 // cast shadows from anything of the map (submodels are optional)
3973 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3975 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3976 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3977 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3978 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3979 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3982 if(ent->entitynumber != 0)
3984 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3985 int entnum, entnum2, recursion;
3986 entnum = entnum2 = ent->entitynumber;
3987 for(recursion = 32; recursion > 0; --recursion)
3989 entnum2 = cl.entities[entnum].state_current.tagentity;
3990 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3995 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3997 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3998 // transform into modelspace of OUR entity
3999 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4000 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4003 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4006 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4009 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4010 RSurf_ActiveModelEntity(ent, false, false);
4011 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4012 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4016 // not really the right mode, but this will disable any silly stencil features
4017 R_Shadow_RenderMode_End();
4019 // set up ortho view for rendering this pass
4020 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4021 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4022 //GL_ScissorTest(true);
4023 //R_Mesh_Matrix(&identitymatrix);
4024 //R_Mesh_ResetTextureState();
4025 R_ResetViewRendering2D();
4026 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4027 R_Mesh_ColorPointer(NULL, 0, 0);
4028 R_SetupGenericShader(false);
4030 // set up a darkening blend on shadowed areas
4031 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4032 //GL_DepthRange(0, 1);
4033 //GL_DepthTest(false);
4034 //GL_DepthMask(false);
4035 //GL_PolygonOffset(0, 0);CHECKGLERROR
4036 GL_Color(0, 0, 0, r_shadows_darken.value);
4037 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4038 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4039 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4040 qglStencilMask(~0);CHECKGLERROR
4041 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4042 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4044 // apply the blend to the shadowed areas
4045 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4047 // restore the viewport
4048 R_SetViewport(&r_refdef.view.viewport);
4050 // restore other state to normal
4051 //R_Shadow_RenderMode_End();
4054 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4057 vec3_t centerorigin;
4058 // if it's too close, skip it
4059 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4061 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4064 if (usequery && r_numqueries + 2 <= r_maxqueries)
4066 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4067 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4068 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4071 // NOTE: we can't disable depth testing using R_DrawSprite's depthdisable argument, which calls GL_DepthTest, as that's broken in the ATI drivers
4072 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4073 qglDepthFunc(GL_ALWAYS);
4074 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4075 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4076 qglDepthFunc(GL_LEQUAL);
4077 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4078 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4079 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4082 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4085 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4088 GLint allpixels = 0, visiblepixels = 0;
4089 // now we have to check the query result
4090 if (rtlight->corona_queryindex_visiblepixels)
4093 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4094 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4096 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4097 if (visiblepixels < 1 || allpixels < 1)
4099 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4100 cscale *= rtlight->corona_visibility;
4104 // FIXME: these traces should scan all render entities instead of cl.world
4105 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4108 VectorScale(rtlight->color, cscale, color);
4109 if (VectorLength(color) > (1.0f / 256.0f))
4110 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
4113 void R_DrawCoronas(void)
4121 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4123 if (r_waterstate.renderingscene)
4125 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4126 R_Mesh_Matrix(&identitymatrix);
4128 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4130 // check occlusion of coronas
4131 // use GL_ARB_occlusion_query if available
4132 // otherwise use raytraces
4134 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4137 GL_ColorMask(0,0,0,0);
4138 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4139 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4142 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4143 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4145 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4149 for (lightindex = 0;lightindex < range;lightindex++)
4151 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4154 rtlight = &light->rtlight;
4155 rtlight->corona_visibility = 0;
4156 rtlight->corona_queryindex_visiblepixels = 0;
4157 rtlight->corona_queryindex_allpixels = 0;
4158 if (!(rtlight->flags & flag))
4160 if (rtlight->corona <= 0)
4162 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4164 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4166 for (i = 0;i < r_refdef.scene.numlights;i++)
4168 rtlight = r_refdef.scene.lights[i];
4169 rtlight->corona_visibility = 0;
4170 rtlight->corona_queryindex_visiblepixels = 0;
4171 rtlight->corona_queryindex_allpixels = 0;
4172 if (!(rtlight->flags & flag))
4174 if (rtlight->corona <= 0)
4176 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4179 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4181 // now draw the coronas using the query data for intensity info
4182 for (lightindex = 0;lightindex < range;lightindex++)
4184 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4187 rtlight = &light->rtlight;
4188 if (rtlight->corona_visibility <= 0)
4190 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4192 for (i = 0;i < r_refdef.scene.numlights;i++)
4194 rtlight = r_refdef.scene.lights[i];
4195 if (rtlight->corona_visibility <= 0)
4197 if (gl_flashblend.integer)
4198 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4200 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4206 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4207 typedef struct suffixinfo_s
4210 qboolean flipx, flipy, flipdiagonal;
4213 static suffixinfo_t suffix[3][6] =
4216 {"px", false, false, false},
4217 {"nx", false, false, false},
4218 {"py", false, false, false},
4219 {"ny", false, false, false},
4220 {"pz", false, false, false},
4221 {"nz", false, false, false}
4224 {"posx", false, false, false},
4225 {"negx", false, false, false},
4226 {"posy", false, false, false},
4227 {"negy", false, false, false},
4228 {"posz", false, false, false},
4229 {"negz", false, false, false}
4232 {"rt", true, false, true},
4233 {"lf", false, true, true},
4234 {"ft", true, true, false},
4235 {"bk", false, false, false},
4236 {"up", true, false, true},
4237 {"dn", true, false, true}
4241 static int componentorder[4] = {0, 1, 2, 3};
4243 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4245 int i, j, cubemapsize;
4246 unsigned char *cubemappixels, *image_buffer;
4247 rtexture_t *cubemaptexture;
4249 // must start 0 so the first loadimagepixels has no requested width/height
4251 cubemappixels = NULL;
4252 cubemaptexture = NULL;
4253 // keep trying different suffix groups (posx, px, rt) until one loads
4254 for (j = 0;j < 3 && !cubemappixels;j++)
4256 // load the 6 images in the suffix group
4257 for (i = 0;i < 6;i++)
4259 // generate an image name based on the base and and suffix
4260 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4262 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4264 // an image loaded, make sure width and height are equal
4265 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4267 // if this is the first image to load successfully, allocate the cubemap memory
4268 if (!cubemappixels && image_width >= 1)
4270 cubemapsize = image_width;
4271 // note this clears to black, so unavailable sides are black
4272 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4274 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4276 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);
4279 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4281 Mem_Free(image_buffer);
4285 // if a cubemap loaded, upload it
4288 if (developer_loading.integer)
4289 Con_Printf("loading cubemap \"%s\"\n", basename);
4291 if (!r_shadow_filters_texturepool)
4292 r_shadow_filters_texturepool = R_AllocTexturePool();
4293 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4294 Mem_Free(cubemappixels);
4298 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4299 if (developer_loading.integer)
4301 Con_Printf("(tried tried images ");
4302 for (j = 0;j < 3;j++)
4303 for (i = 0;i < 6;i++)
4304 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4305 Con_Print(" and was unable to find any of them).\n");
4308 return cubemaptexture;
4311 rtexture_t *R_Shadow_Cubemap(const char *basename)
4314 for (i = 0;i < numcubemaps;i++)
4315 if (!strcasecmp(cubemaps[i].basename, basename))
4316 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4317 if (i >= MAX_CUBEMAPS)
4318 return r_texture_whitecube;
4320 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4321 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4322 return cubemaps[i].texture;
4325 void R_Shadow_FreeCubemaps(void)
4328 for (i = 0;i < numcubemaps;i++)
4330 if (developer_loading.integer)
4331 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4332 if (cubemaps[i].texture)
4333 R_FreeTexture(cubemaps[i].texture);
4337 R_FreeTexturePool(&r_shadow_filters_texturepool);
4340 dlight_t *R_Shadow_NewWorldLight(void)
4342 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4345 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)
4348 // validate parameters
4349 if (style < 0 || style >= MAX_LIGHTSTYLES)
4351 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4357 // copy to light properties
4358 VectorCopy(origin, light->origin);
4359 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4360 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4361 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4362 light->color[0] = max(color[0], 0);
4363 light->color[1] = max(color[1], 0);
4364 light->color[2] = max(color[2], 0);
4365 light->radius = max(radius, 0);
4366 light->style = style;
4367 light->shadow = shadowenable;
4368 light->corona = corona;
4369 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4370 light->coronasizescale = coronasizescale;
4371 light->ambientscale = ambientscale;
4372 light->diffusescale = diffusescale;
4373 light->specularscale = specularscale;
4374 light->flags = flags;
4376 // update renderable light data
4377 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4378 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);
4381 void R_Shadow_FreeWorldLight(dlight_t *light)
4383 if (r_shadow_selectedlight == light)
4384 r_shadow_selectedlight = NULL;
4385 R_RTLight_Uncompile(&light->rtlight);
4386 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4389 void R_Shadow_ClearWorldLights(void)
4393 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4394 for (lightindex = 0;lightindex < range;lightindex++)
4396 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4398 R_Shadow_FreeWorldLight(light);
4400 r_shadow_selectedlight = NULL;
4401 R_Shadow_FreeCubemaps();
4404 void R_Shadow_SelectLight(dlight_t *light)
4406 if (r_shadow_selectedlight)
4407 r_shadow_selectedlight->selected = false;
4408 r_shadow_selectedlight = light;
4409 if (r_shadow_selectedlight)
4410 r_shadow_selectedlight->selected = true;
4413 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4415 // this is never batched (there can be only one)
4416 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
4419 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4426 // this is never batched (due to the ent parameter changing every time)
4427 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4428 const dlight_t *light = (dlight_t *)ent;
4431 VectorScale(light->color, intensity, spritecolor);
4432 if (VectorLength(spritecolor) < 0.1732f)
4433 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4434 if (VectorLength(spritecolor) > 1.0f)
4435 VectorNormalize(spritecolor);
4437 // draw light sprite
4438 if (light->cubemapname[0] && !light->shadow)
4439 pic = r_editlights_sprcubemapnoshadowlight;
4440 else if (light->cubemapname[0])
4441 pic = r_editlights_sprcubemaplight;
4442 else if (!light->shadow)
4443 pic = r_editlights_sprnoshadowlight;
4445 pic = r_editlights_sprlight;
4446 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
4447 // draw selection sprite if light is selected
4448 if (light->selected)
4449 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
4450 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4453 void R_Shadow_DrawLightSprites(void)
4457 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4458 for (lightindex = 0;lightindex < range;lightindex++)
4460 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4462 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4464 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4467 void R_Shadow_SelectLightInView(void)
4469 float bestrating, rating, temp[3];
4473 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4476 for (lightindex = 0;lightindex < range;lightindex++)
4478 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4481 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4482 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4485 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4486 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4488 bestrating = rating;
4493 R_Shadow_SelectLight(best);
4496 void R_Shadow_LoadWorldLights(void)
4498 int n, a, style, shadow, flags;
4499 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4500 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4501 if (cl.worldmodel == NULL)
4503 Con_Print("No map loaded.\n");
4506 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4507 strlcat (name, ".rtlights", sizeof (name));
4508 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4518 for (;COM_Parse(t, true) && strcmp(
4519 if (COM_Parse(t, true))
4521 if (com_token[0] == '!')
4524 origin[0] = atof(com_token+1);
4527 origin[0] = atof(com_token);
4532 while (*s && *s != '\n' && *s != '\r')
4538 // check for modifier flags
4545 #if _MSC_VER >= 1400
4546 #define sscanf sscanf_s
4548 cubemapname[sizeof(cubemapname)-1] = 0;
4549 #if MAX_QPATH != 128
4550 #error update this code if MAX_QPATH changes
4552 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
4553 #if _MSC_VER >= 1400
4554 , sizeof(cubemapname)
4556 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4559 flags = LIGHTFLAG_REALTIMEMODE;
4567 coronasizescale = 0.25f;
4569 VectorClear(angles);
4572 if (a < 9 || !strcmp(cubemapname, "\"\""))
4574 // remove quotes on cubemapname
4575 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4578 namelen = strlen(cubemapname) - 2;
4579 memmove(cubemapname, cubemapname + 1, namelen);
4580 cubemapname[namelen] = '\0';
4584 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);
4587 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4595 Con_Printf("invalid rtlights file \"%s\"\n", name);
4596 Mem_Free(lightsstring);
4600 void R_Shadow_SaveWorldLights(void)
4604 size_t bufchars, bufmaxchars;
4606 char name[MAX_QPATH];
4607 char line[MAX_INPUTLINE];
4608 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4609 // I hate lines which are 3 times my screen size :( --blub
4612 if (cl.worldmodel == NULL)
4614 Con_Print("No map loaded.\n");
4617 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4618 strlcat (name, ".rtlights", sizeof (name));
4619 bufchars = bufmaxchars = 0;
4621 for (lightindex = 0;lightindex < range;lightindex++)
4623 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4626 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4627 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);
4628 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4629 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]);
4631 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);
4632 if (bufchars + strlen(line) > bufmaxchars)
4634 bufmaxchars = bufchars + strlen(line) + 2048;
4636 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4640 memcpy(buf, oldbuf, bufchars);
4646 memcpy(buf + bufchars, line, strlen(line));
4647 bufchars += strlen(line);
4651 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4656 void R_Shadow_LoadLightsFile(void)
4659 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4660 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4661 if (cl.worldmodel == NULL)
4663 Con_Print("No map loaded.\n");
4666 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4667 strlcat (name, ".lights", sizeof (name));
4668 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4676 while (*s && *s != '\n' && *s != '\r')
4682 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);
4686 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);
4689 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4690 radius = bound(15, radius, 4096);
4691 VectorScale(color, (2.0f / (8388608.0f)), color);
4692 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4700 Con_Printf("invalid lights file \"%s\"\n", name);
4701 Mem_Free(lightsstring);
4705 // tyrlite/hmap2 light types in the delay field
4706 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4708 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4710 int entnum, style, islight, skin, pflags, effects, type, n;
4713 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4714 char key[256], value[MAX_INPUTLINE];
4716 if (cl.worldmodel == NULL)
4718 Con_Print("No map loaded.\n");
4721 // try to load a .ent file first
4722 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4723 strlcat (key, ".ent", sizeof (key));
4724 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4725 // and if that is not found, fall back to the bsp file entity string
4727 data = cl.worldmodel->brush.entities;
4730 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4732 type = LIGHTTYPE_MINUSX;
4733 origin[0] = origin[1] = origin[2] = 0;
4734 originhack[0] = originhack[1] = originhack[2] = 0;
4735 angles[0] = angles[1] = angles[2] = 0;
4736 color[0] = color[1] = color[2] = 1;
4737 light[0] = light[1] = light[2] = 1;light[3] = 300;
4738 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4748 if (!COM_ParseToken_Simple(&data, false, false))
4750 if (com_token[0] == '}')
4751 break; // end of entity
4752 if (com_token[0] == '_')
4753 strlcpy(key, com_token + 1, sizeof(key));
4755 strlcpy(key, com_token, sizeof(key));
4756 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4757 key[strlen(key)-1] = 0;
4758 if (!COM_ParseToken_Simple(&data, false, false))
4760 strlcpy(value, com_token, sizeof(value));
4762 // now that we have the key pair worked out...
4763 if (!strcmp("light", key))
4765 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4769 light[0] = vec[0] * (1.0f / 256.0f);
4770 light[1] = vec[0] * (1.0f / 256.0f);
4771 light[2] = vec[0] * (1.0f / 256.0f);
4777 light[0] = vec[0] * (1.0f / 255.0f);
4778 light[1] = vec[1] * (1.0f / 255.0f);
4779 light[2] = vec[2] * (1.0f / 255.0f);
4783 else if (!strcmp("delay", key))
4785 else if (!strcmp("origin", key))
4786 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4787 else if (!strcmp("angle", key))
4788 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4789 else if (!strcmp("angles", key))
4790 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4791 else if (!strcmp("color", key))
4792 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4793 else if (!strcmp("wait", key))
4794 fadescale = atof(value);
4795 else if (!strcmp("classname", key))
4797 if (!strncmp(value, "light", 5))
4800 if (!strcmp(value, "light_fluoro"))
4805 overridecolor[0] = 1;
4806 overridecolor[1] = 1;
4807 overridecolor[2] = 1;
4809 if (!strcmp(value, "light_fluorospark"))
4814 overridecolor[0] = 1;
4815 overridecolor[1] = 1;
4816 overridecolor[2] = 1;
4818 if (!strcmp(value, "light_globe"))
4823 overridecolor[0] = 1;
4824 overridecolor[1] = 0.8;
4825 overridecolor[2] = 0.4;
4827 if (!strcmp(value, "light_flame_large_yellow"))
4832 overridecolor[0] = 1;
4833 overridecolor[1] = 0.5;
4834 overridecolor[2] = 0.1;
4836 if (!strcmp(value, "light_flame_small_yellow"))
4841 overridecolor[0] = 1;
4842 overridecolor[1] = 0.5;
4843 overridecolor[2] = 0.1;
4845 if (!strcmp(value, "light_torch_small_white"))
4850 overridecolor[0] = 1;
4851 overridecolor[1] = 0.5;
4852 overridecolor[2] = 0.1;
4854 if (!strcmp(value, "light_torch_small_walltorch"))
4859 overridecolor[0] = 1;
4860 overridecolor[1] = 0.5;
4861 overridecolor[2] = 0.1;
4865 else if (!strcmp("style", key))
4866 style = atoi(value);
4867 else if (!strcmp("skin", key))
4868 skin = (int)atof(value);
4869 else if (!strcmp("pflags", key))
4870 pflags = (int)atof(value);
4871 else if (!strcmp("effects", key))
4872 effects = (int)atof(value);
4873 else if (cl.worldmodel->type == mod_brushq3)
4875 if (!strcmp("scale", key))
4876 lightscale = atof(value);
4877 if (!strcmp("fade", key))
4878 fadescale = atof(value);
4883 if (lightscale <= 0)
4887 if (color[0] == color[1] && color[0] == color[2])
4889 color[0] *= overridecolor[0];
4890 color[1] *= overridecolor[1];
4891 color[2] *= overridecolor[2];
4893 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4894 color[0] = color[0] * light[0];
4895 color[1] = color[1] * light[1];
4896 color[2] = color[2] * light[2];
4899 case LIGHTTYPE_MINUSX:
4901 case LIGHTTYPE_RECIPX:
4903 VectorScale(color, (1.0f / 16.0f), color);
4905 case LIGHTTYPE_RECIPXX:
4907 VectorScale(color, (1.0f / 16.0f), color);
4910 case LIGHTTYPE_NONE:
4914 case LIGHTTYPE_MINUSXX:
4917 VectorAdd(origin, originhack, origin);
4919 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);
4922 Mem_Free(entfiledata);
4926 void R_Shadow_SetCursorLocationForView(void)
4929 vec3_t dest, endpos;
4931 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4932 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4933 if (trace.fraction < 1)
4935 dist = trace.fraction * r_editlights_cursordistance.value;
4936 push = r_editlights_cursorpushback.value;
4940 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4941 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4945 VectorClear( endpos );
4947 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4948 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4949 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4952 void R_Shadow_UpdateWorldLightSelection(void)
4954 if (r_editlights.integer)
4956 R_Shadow_SetCursorLocationForView();
4957 R_Shadow_SelectLightInView();
4960 R_Shadow_SelectLight(NULL);
4963 void R_Shadow_EditLights_Clear_f(void)
4965 R_Shadow_ClearWorldLights();
4968 void R_Shadow_EditLights_Reload_f(void)
4972 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4973 R_Shadow_ClearWorldLights();
4974 R_Shadow_LoadWorldLights();
4975 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4977 R_Shadow_LoadLightsFile();
4978 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4979 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4983 void R_Shadow_EditLights_Save_f(void)
4987 R_Shadow_SaveWorldLights();
4990 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4992 R_Shadow_ClearWorldLights();
4993 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4996 void R_Shadow_EditLights_ImportLightsFile_f(void)
4998 R_Shadow_ClearWorldLights();
4999 R_Shadow_LoadLightsFile();
5002 void R_Shadow_EditLights_Spawn_f(void)
5005 if (!r_editlights.integer)
5007 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5010 if (Cmd_Argc() != 1)
5012 Con_Print("r_editlights_spawn does not take parameters\n");
5015 color[0] = color[1] = color[2] = 1;
5016 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5019 void R_Shadow_EditLights_Edit_f(void)
5021 vec3_t origin, angles, color;
5022 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5023 int style, shadows, flags, normalmode, realtimemode;
5024 char cubemapname[MAX_INPUTLINE];
5025 if (!r_editlights.integer)
5027 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5030 if (!r_shadow_selectedlight)
5032 Con_Print("No selected light.\n");
5035 VectorCopy(r_shadow_selectedlight->origin, origin);
5036 VectorCopy(r_shadow_selectedlight->angles, angles);
5037 VectorCopy(r_shadow_selectedlight->color, color);
5038 radius = r_shadow_selectedlight->radius;
5039 style = r_shadow_selectedlight->style;
5040 if (r_shadow_selectedlight->cubemapname)
5041 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5044 shadows = r_shadow_selectedlight->shadow;
5045 corona = r_shadow_selectedlight->corona;
5046 coronasizescale = r_shadow_selectedlight->coronasizescale;
5047 ambientscale = r_shadow_selectedlight->ambientscale;
5048 diffusescale = r_shadow_selectedlight->diffusescale;
5049 specularscale = r_shadow_selectedlight->specularscale;
5050 flags = r_shadow_selectedlight->flags;
5051 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5052 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5053 if (!strcmp(Cmd_Argv(1), "origin"))
5055 if (Cmd_Argc() != 5)
5057 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5060 origin[0] = atof(Cmd_Argv(2));
5061 origin[1] = atof(Cmd_Argv(3));
5062 origin[2] = atof(Cmd_Argv(4));
5064 else if (!strcmp(Cmd_Argv(1), "originx"))
5066 if (Cmd_Argc() != 3)
5068 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5071 origin[0] = atof(Cmd_Argv(2));
5073 else if (!strcmp(Cmd_Argv(1), "originy"))
5075 if (Cmd_Argc() != 3)
5077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5080 origin[1] = atof(Cmd_Argv(2));
5082 else if (!strcmp(Cmd_Argv(1), "originz"))
5084 if (Cmd_Argc() != 3)
5086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5089 origin[2] = atof(Cmd_Argv(2));
5091 else if (!strcmp(Cmd_Argv(1), "move"))
5093 if (Cmd_Argc() != 5)
5095 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5098 origin[0] += atof(Cmd_Argv(2));
5099 origin[1] += atof(Cmd_Argv(3));
5100 origin[2] += atof(Cmd_Argv(4));
5102 else if (!strcmp(Cmd_Argv(1), "movex"))
5104 if (Cmd_Argc() != 3)
5106 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5109 origin[0] += atof(Cmd_Argv(2));
5111 else if (!strcmp(Cmd_Argv(1), "movey"))
5113 if (Cmd_Argc() != 3)
5115 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5118 origin[1] += atof(Cmd_Argv(2));
5120 else if (!strcmp(Cmd_Argv(1), "movez"))
5122 if (Cmd_Argc() != 3)
5124 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5127 origin[2] += atof(Cmd_Argv(2));
5129 else if (!strcmp(Cmd_Argv(1), "angles"))
5131 if (Cmd_Argc() != 5)
5133 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5136 angles[0] = atof(Cmd_Argv(2));
5137 angles[1] = atof(Cmd_Argv(3));
5138 angles[2] = atof(Cmd_Argv(4));
5140 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5142 if (Cmd_Argc() != 3)
5144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5147 angles[0] = atof(Cmd_Argv(2));
5149 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5151 if (Cmd_Argc() != 3)
5153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5156 angles[1] = atof(Cmd_Argv(2));
5158 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5160 if (Cmd_Argc() != 3)
5162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5165 angles[2] = atof(Cmd_Argv(2));
5167 else if (!strcmp(Cmd_Argv(1), "color"))
5169 if (Cmd_Argc() != 5)
5171 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5174 color[0] = atof(Cmd_Argv(2));
5175 color[1] = atof(Cmd_Argv(3));
5176 color[2] = atof(Cmd_Argv(4));
5178 else if (!strcmp(Cmd_Argv(1), "radius"))
5180 if (Cmd_Argc() != 3)
5182 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5185 radius = atof(Cmd_Argv(2));
5187 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5189 if (Cmd_Argc() == 3)
5191 double scale = atof(Cmd_Argv(2));
5198 if (Cmd_Argc() != 5)
5200 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5203 color[0] *= atof(Cmd_Argv(2));
5204 color[1] *= atof(Cmd_Argv(3));
5205 color[2] *= atof(Cmd_Argv(4));
5208 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5210 if (Cmd_Argc() != 3)
5212 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5215 radius *= atof(Cmd_Argv(2));
5217 else if (!strcmp(Cmd_Argv(1), "style"))
5219 if (Cmd_Argc() != 3)
5221 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5224 style = atoi(Cmd_Argv(2));
5226 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5230 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5233 if (Cmd_Argc() == 3)
5234 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5238 else if (!strcmp(Cmd_Argv(1), "shadows"))
5240 if (Cmd_Argc() != 3)
5242 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5245 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5247 else if (!strcmp(Cmd_Argv(1), "corona"))
5249 if (Cmd_Argc() != 3)
5251 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5254 corona = atof(Cmd_Argv(2));
5256 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5258 if (Cmd_Argc() != 3)
5260 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5263 coronasizescale = atof(Cmd_Argv(2));
5265 else if (!strcmp(Cmd_Argv(1), "ambient"))
5267 if (Cmd_Argc() != 3)
5269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5272 ambientscale = atof(Cmd_Argv(2));
5274 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5276 if (Cmd_Argc() != 3)
5278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5281 diffusescale = atof(Cmd_Argv(2));
5283 else if (!strcmp(Cmd_Argv(1), "specular"))
5285 if (Cmd_Argc() != 3)
5287 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5290 specularscale = atof(Cmd_Argv(2));
5292 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5294 if (Cmd_Argc() != 3)
5296 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5299 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5301 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5303 if (Cmd_Argc() != 3)
5305 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5308 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5312 Con_Print("usage: r_editlights_edit [property] [value]\n");
5313 Con_Print("Selected light's properties:\n");
5314 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5315 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5316 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5317 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5318 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5319 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5320 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5321 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5322 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5323 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5324 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5325 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5326 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5327 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5330 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5331 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5334 void R_Shadow_EditLights_EditAll_f(void)
5340 if (!r_editlights.integer)
5342 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5346 // EditLights doesn't seem to have a "remove" command or something so:
5347 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5348 for (lightindex = 0;lightindex < range;lightindex++)
5350 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5353 R_Shadow_SelectLight(light);
5354 R_Shadow_EditLights_Edit_f();
5358 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5360 int lightnumber, lightcount;
5361 size_t lightindex, range;
5365 if (!r_editlights.integer)
5367 x = vid_conwidth.value - 240;
5369 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5372 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5373 for (lightindex = 0;lightindex < range;lightindex++)
5375 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5378 if (light == r_shadow_selectedlight)
5379 lightnumber = lightindex;
5382 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;
5383 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;
5385 if (r_shadow_selectedlight == NULL)
5387 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;
5388 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;
5389 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;
5390 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;
5391 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;
5392 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;
5393 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;
5394 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;
5395 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;
5396 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;
5397 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;
5398 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;
5399 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;
5400 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;
5401 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;
5404 void R_Shadow_EditLights_ToggleShadow_f(void)
5406 if (!r_editlights.integer)
5408 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5411 if (!r_shadow_selectedlight)
5413 Con_Print("No selected light.\n");
5416 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);
5419 void R_Shadow_EditLights_ToggleCorona_f(void)
5421 if (!r_editlights.integer)
5423 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5426 if (!r_shadow_selectedlight)
5428 Con_Print("No selected light.\n");
5431 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);
5434 void R_Shadow_EditLights_Remove_f(void)
5436 if (!r_editlights.integer)
5438 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5441 if (!r_shadow_selectedlight)
5443 Con_Print("No selected light.\n");
5446 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5447 r_shadow_selectedlight = NULL;
5450 void R_Shadow_EditLights_Help_f(void)
5453 "Documentation on r_editlights system:\n"
5455 "r_editlights : enable/disable editing mode\n"
5456 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5457 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5458 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5459 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5460 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5462 "r_editlights_help : this help\n"
5463 "r_editlights_clear : remove all lights\n"
5464 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5465 "r_editlights_save : save to .rtlights file\n"
5466 "r_editlights_spawn : create a light with default settings\n"
5467 "r_editlights_edit command : edit selected light - more documentation below\n"
5468 "r_editlights_remove : remove selected light\n"
5469 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5470 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5471 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5473 "origin x y z : set light location\n"
5474 "originx x: set x component of light location\n"
5475 "originy y: set y component of light location\n"
5476 "originz z: set z component of light location\n"
5477 "move x y z : adjust light location\n"
5478 "movex x: adjust x component of light location\n"
5479 "movey y: adjust y component of light location\n"
5480 "movez z: adjust z component of light location\n"
5481 "angles x y z : set light angles\n"
5482 "anglesx x: set x component of light angles\n"
5483 "anglesy y: set y component of light angles\n"
5484 "anglesz z: set z component of light angles\n"
5485 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5486 "radius radius : set radius (size) of light\n"
5487 "colorscale grey : multiply color of light (1 does nothing)\n"
5488 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5489 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5490 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5491 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5492 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5493 "shadows 1/0 : turn on/off shadows\n"
5494 "corona n : set corona intensity\n"
5495 "coronasize n : set corona size (0-1)\n"
5496 "ambient n : set ambient intensity (0-1)\n"
5497 "diffuse n : set diffuse intensity (0-1)\n"
5498 "specular n : set specular intensity (0-1)\n"
5499 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5500 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5501 "<nothing> : print light properties to console\n"
5505 void R_Shadow_EditLights_CopyInfo_f(void)
5507 if (!r_editlights.integer)
5509 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5512 if (!r_shadow_selectedlight)
5514 Con_Print("No selected light.\n");
5517 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5518 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5519 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5520 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5521 if (r_shadow_selectedlight->cubemapname)
5522 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5524 r_shadow_bufferlight.cubemapname[0] = 0;
5525 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5526 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5527 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5528 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5529 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5530 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5531 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5534 void R_Shadow_EditLights_PasteInfo_f(void)
5536 if (!r_editlights.integer)
5538 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5541 if (!r_shadow_selectedlight)
5543 Con_Print("No selected light.\n");
5546 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);
5549 void R_Shadow_EditLights_Init(void)
5551 Cvar_RegisterVariable(&r_editlights);
5552 Cvar_RegisterVariable(&r_editlights_cursordistance);
5553 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5554 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5555 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5556 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5557 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5558 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5559 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)");
5560 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5561 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5562 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5563 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)");
5564 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5565 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5566 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5567 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5568 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5569 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5570 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)");
5576 =============================================================================
5580 =============================================================================
5583 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5585 VectorClear(diffusecolor);
5586 VectorClear(diffusenormal);
5588 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5590 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5591 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5594 VectorSet(ambientcolor, 1, 1, 1);
5601 for (i = 0;i < r_refdef.scene.numlights;i++)
5603 light = r_refdef.scene.lights[i];
5604 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5605 f = 1 - VectorLength2(v);
5606 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5607 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);