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_shadowmapmaxsize;
183 int r_shadow_shadowmapfilter;
184 int r_shadow_shadowmapborder;
185 int r_shadow_lightscissor[4];
187 int maxshadowtriangles;
190 int maxshadowvertices;
191 float *shadowvertex3f;
204 int r_shadow_buffer_numleafpvsbytes;
205 unsigned char *r_shadow_buffer_visitingleafpvs;
206 unsigned char *r_shadow_buffer_leafpvs;
207 int *r_shadow_buffer_leaflist;
209 int r_shadow_buffer_numsurfacepvsbytes;
210 unsigned char *r_shadow_buffer_surfacepvs;
211 int *r_shadow_buffer_surfacelist;
213 int r_shadow_buffer_numshadowtrispvsbytes;
214 unsigned char *r_shadow_buffer_shadowtrispvs;
215 int r_shadow_buffer_numlighttrispvsbytes;
216 unsigned char *r_shadow_buffer_lighttrispvs;
218 rtexturepool_t *r_shadow_texturepool;
219 rtexture_t *r_shadow_attenuationgradienttexture;
220 rtexture_t *r_shadow_attenuation2dtexture;
221 rtexture_t *r_shadow_attenuation3dtexture;
222 rtexture_t *r_shadow_lightcorona;
223 rtexture_t *r_shadow_shadowmaprectangletexture;
224 rtexture_t *r_shadow_shadowmap2dtexture;
225 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
226 rtexture_t *r_shadow_shadowmapcubeprojectiontexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
227 int r_shadow_shadowmapsize; // changes for each light based on distance
228 int r_shadow_shadowmaplod; // changes for each light based on distance
230 // lights are reloaded when this changes
231 char r_shadow_mapname[MAX_QPATH];
233 // used only for light filters (cubemaps)
234 rtexturepool_t *r_shadow_filters_texturepool;
236 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"};
237 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"};
238 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
239 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
240 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)"};
241 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"};
242 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
243 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
244 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
245 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
246 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
247 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
248 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
249 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
250 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
251 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)"};
252 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
253 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
254 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
255 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
256 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)"};
257 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"};
258 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
259 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
260 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"};
261 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
262 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
263 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)"};
264 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"};
265 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
266 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
267 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
268 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
269 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
270 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
271 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
272 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
273 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
274 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
275 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)"};
276 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)"};
277 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
278 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"};
279 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
280 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
281 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
282 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
283 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
284 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
285 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
286 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
287 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
288 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
290 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
291 #define ATTENTABLESIZE 256
292 // 1D gradient, 2D circle and 3D sphere attenuation textures
293 #define ATTEN1DSIZE 32
294 #define ATTEN2DSIZE 64
295 #define ATTEN3DSIZE 32
297 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
298 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
299 static float r_shadow_attentable[ATTENTABLESIZE+1];
301 rtlight_t *r_shadow_compilingrtlight;
302 static memexpandablearray_t r_shadow_worldlightsarray;
303 dlight_t *r_shadow_selectedlight;
304 dlight_t r_shadow_bufferlight;
305 vec3_t r_editlights_cursorlocation;
307 extern int con_vislines;
309 typedef struct cubemapinfo_s
316 #define MAX_CUBEMAPS 256
317 static int numcubemaps;
318 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
320 void R_Shadow_UncompileWorldLights(void);
321 void R_Shadow_ClearWorldLights(void);
322 void R_Shadow_SaveWorldLights(void);
323 void R_Shadow_LoadWorldLights(void);
324 void R_Shadow_LoadLightsFile(void);
325 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
326 void R_Shadow_EditLights_Reload_f(void);
327 void R_Shadow_ValidateCvars(void);
328 static void R_Shadow_MakeTextures(void);
330 // VorteX: custom editor light sprites
331 #define EDLIGHTSPRSIZE 8
332 cachepic_t *r_editlights_sprcursor;
333 cachepic_t *r_editlights_sprlight;
334 cachepic_t *r_editlights_sprnoshadowlight;
335 cachepic_t *r_editlights_sprcubemaplight;
336 cachepic_t *r_editlights_sprcubemapnoshadowlight;
337 cachepic_t *r_editlights_sprselection;
339 void R_Shadow_FreeShadowMaps(void)
343 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
344 r_shadow_shadowmode = r_shadow_shadowmapping.integer;
345 r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer;
346 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
347 r_shadow_shadowmaplod = -1;
350 if (r_shadow_fborectangle)
351 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
352 r_shadow_fborectangle = 0;
356 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
359 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
360 if (r_shadow_fbocubeside[i][0])
361 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
362 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
365 if (r_shadow_shadowmaprectangletexture)
366 R_FreeTexture(r_shadow_shadowmaprectangletexture);
367 r_shadow_shadowmaprectangletexture = NULL;
369 if (r_shadow_shadowmap2dtexture)
370 R_FreeTexture(r_shadow_shadowmap2dtexture);
371 r_shadow_shadowmap2dtexture = NULL;
373 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
374 if (r_shadow_shadowmapcubetexture[i])
375 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
376 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
378 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
379 if (r_shadow_shadowmapcubeprojectiontexture[i])
380 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]);
381 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
386 void r_shadow_start(void)
388 // allocate vertex processing arrays
390 r_shadow_attenuationgradienttexture = NULL;
391 r_shadow_attenuation2dtexture = NULL;
392 r_shadow_attenuation3dtexture = NULL;
393 r_shadow_shadowmode = 0;
394 r_shadow_shadowmaprectangletexture = NULL;
395 r_shadow_shadowmap2dtexture = NULL;
396 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
397 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
398 r_shadow_shadowmapmaxsize = 0;
399 r_shadow_shadowmapsize = 0;
400 r_shadow_shadowmaplod = 0;
401 r_shadow_shadowmapfilter = 0;
402 r_shadow_fborectangle = 0;
404 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
406 R_Shadow_FreeShadowMaps();
408 r_shadow_texturepool = NULL;
409 r_shadow_filters_texturepool = NULL;
410 R_Shadow_ValidateCvars();
411 R_Shadow_MakeTextures();
412 maxshadowtriangles = 0;
413 shadowelements = NULL;
414 maxshadowvertices = 0;
415 shadowvertex3f = NULL;
423 shadowmarklist = NULL;
425 r_shadow_buffer_numleafpvsbytes = 0;
426 r_shadow_buffer_visitingleafpvs = NULL;
427 r_shadow_buffer_leafpvs = NULL;
428 r_shadow_buffer_leaflist = NULL;
429 r_shadow_buffer_numsurfacepvsbytes = 0;
430 r_shadow_buffer_surfacepvs = NULL;
431 r_shadow_buffer_surfacelist = NULL;
432 r_shadow_buffer_numshadowtrispvsbytes = 0;
433 r_shadow_buffer_shadowtrispvs = NULL;
434 r_shadow_buffer_numlighttrispvsbytes = 0;
435 r_shadow_buffer_lighttrispvs = NULL;
438 void r_shadow_shutdown(void)
441 R_Shadow_UncompileWorldLights();
443 R_Shadow_FreeShadowMaps();
447 r_shadow_attenuationgradienttexture = NULL;
448 r_shadow_attenuation2dtexture = NULL;
449 r_shadow_attenuation3dtexture = NULL;
450 R_FreeTexturePool(&r_shadow_texturepool);
451 R_FreeTexturePool(&r_shadow_filters_texturepool);
452 maxshadowtriangles = 0;
454 Mem_Free(shadowelements);
455 shadowelements = NULL;
457 Mem_Free(shadowvertex3f);
458 shadowvertex3f = NULL;
461 Mem_Free(vertexupdate);
464 Mem_Free(vertexremap);
470 Mem_Free(shadowmark);
473 Mem_Free(shadowmarklist);
474 shadowmarklist = NULL;
476 r_shadow_buffer_numleafpvsbytes = 0;
477 if (r_shadow_buffer_visitingleafpvs)
478 Mem_Free(r_shadow_buffer_visitingleafpvs);
479 r_shadow_buffer_visitingleafpvs = NULL;
480 if (r_shadow_buffer_leafpvs)
481 Mem_Free(r_shadow_buffer_leafpvs);
482 r_shadow_buffer_leafpvs = NULL;
483 if (r_shadow_buffer_leaflist)
484 Mem_Free(r_shadow_buffer_leaflist);
485 r_shadow_buffer_leaflist = NULL;
486 r_shadow_buffer_numsurfacepvsbytes = 0;
487 if (r_shadow_buffer_surfacepvs)
488 Mem_Free(r_shadow_buffer_surfacepvs);
489 r_shadow_buffer_surfacepvs = NULL;
490 if (r_shadow_buffer_surfacelist)
491 Mem_Free(r_shadow_buffer_surfacelist);
492 r_shadow_buffer_surfacelist = NULL;
493 r_shadow_buffer_numshadowtrispvsbytes = 0;
494 if (r_shadow_buffer_shadowtrispvs)
495 Mem_Free(r_shadow_buffer_shadowtrispvs);
496 r_shadow_buffer_numlighttrispvsbytes = 0;
497 if (r_shadow_buffer_lighttrispvs)
498 Mem_Free(r_shadow_buffer_lighttrispvs);
501 void r_shadow_newmap(void)
503 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
504 R_Shadow_EditLights_Reload_f();
507 void R_Shadow_Help_f(void)
510 "Documentation on r_shadow system:\n"
512 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
513 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
514 "r_shadow_debuglight : render only this light number (-1 = all)\n"
515 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
516 "r_shadow_gloss2intensity : brightness of forced gloss\n"
517 "r_shadow_glossintensity : brightness of textured gloss\n"
518 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
519 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
520 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
521 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
522 "r_shadow_portallight : use portal visibility for static light precomputation\n"
523 "r_shadow_projectdistance : shadow volume projection distance\n"
524 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
525 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
526 "r_shadow_realtime_world : use high quality world lighting mode\n"
527 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
528 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
529 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
530 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
531 "r_shadow_scissor : use scissor optimization\n"
532 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
533 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
534 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
535 "r_showlighting : useful for performance testing; bright = slow!\n"
536 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
538 "r_shadow_help : this help\n"
542 void R_Shadow_Init(void)
544 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
545 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
546 Cvar_RegisterVariable(&r_shadow_usenormalmap);
547 Cvar_RegisterVariable(&r_shadow_debuglight);
548 Cvar_RegisterVariable(&r_shadow_gloss);
549 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
550 Cvar_RegisterVariable(&r_shadow_glossintensity);
551 Cvar_RegisterVariable(&r_shadow_glossexponent);
552 Cvar_RegisterVariable(&r_shadow_glossexact);
553 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
554 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
555 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
556 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
557 Cvar_RegisterVariable(&r_shadow_portallight);
558 Cvar_RegisterVariable(&r_shadow_projectdistance);
559 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
560 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
561 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
562 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
563 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
564 Cvar_RegisterVariable(&r_shadow_realtime_world);
565 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
566 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
567 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
568 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
569 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
570 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
571 Cvar_RegisterVariable(&r_shadow_scissor);
572 Cvar_RegisterVariable(&r_shadow_shadowmapping);
573 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
574 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
575 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
576 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
577 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
578 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
579 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
580 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
581 Cvar_RegisterVariable(&r_shadow_culltriangles);
582 Cvar_RegisterVariable(&r_shadow_polygonfactor);
583 Cvar_RegisterVariable(&r_shadow_polygonoffset);
584 Cvar_RegisterVariable(&r_shadow_texture3d);
585 Cvar_RegisterVariable(&r_coronas);
586 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
587 Cvar_RegisterVariable(&r_coronas_occlusionquery);
588 Cvar_RegisterVariable(&gl_flashblend);
589 Cvar_RegisterVariable(&gl_ext_separatestencil);
590 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
591 if (gamemode == GAME_TENEBRAE)
593 Cvar_SetValue("r_shadow_gloss", 2);
594 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
596 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
597 R_Shadow_EditLights_Init();
598 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
599 maxshadowtriangles = 0;
600 shadowelements = NULL;
601 maxshadowvertices = 0;
602 shadowvertex3f = NULL;
610 shadowmarklist = NULL;
612 r_shadow_buffer_numleafpvsbytes = 0;
613 r_shadow_buffer_visitingleafpvs = NULL;
614 r_shadow_buffer_leafpvs = NULL;
615 r_shadow_buffer_leaflist = NULL;
616 r_shadow_buffer_numsurfacepvsbytes = 0;
617 r_shadow_buffer_surfacepvs = NULL;
618 r_shadow_buffer_surfacelist = NULL;
619 r_shadow_buffer_shadowtrispvs = NULL;
620 r_shadow_buffer_lighttrispvs = NULL;
621 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
624 matrix4x4_t matrix_attenuationxyz =
627 {0.5, 0.0, 0.0, 0.5},
628 {0.0, 0.5, 0.0, 0.5},
629 {0.0, 0.0, 0.5, 0.5},
634 matrix4x4_t matrix_attenuationz =
637 {0.0, 0.0, 0.5, 0.5},
638 {0.0, 0.0, 0.0, 0.5},
639 {0.0, 0.0, 0.0, 0.5},
644 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
646 // make sure shadowelements is big enough for this volume
647 if (maxshadowtriangles < numtriangles)
649 maxshadowtriangles = numtriangles;
651 Mem_Free(shadowelements);
652 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
654 // make sure shadowvertex3f is big enough for this volume
655 if (maxshadowvertices < numvertices)
657 maxshadowvertices = numvertices;
659 Mem_Free(shadowvertex3f);
660 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
664 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
666 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
667 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
668 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
669 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
670 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
672 if (r_shadow_buffer_visitingleafpvs)
673 Mem_Free(r_shadow_buffer_visitingleafpvs);
674 if (r_shadow_buffer_leafpvs)
675 Mem_Free(r_shadow_buffer_leafpvs);
676 if (r_shadow_buffer_leaflist)
677 Mem_Free(r_shadow_buffer_leaflist);
678 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
679 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
680 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
681 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
683 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
685 if (r_shadow_buffer_surfacepvs)
686 Mem_Free(r_shadow_buffer_surfacepvs);
687 if (r_shadow_buffer_surfacelist)
688 Mem_Free(r_shadow_buffer_surfacelist);
689 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
690 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
691 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
693 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
695 if (r_shadow_buffer_shadowtrispvs)
696 Mem_Free(r_shadow_buffer_shadowtrispvs);
697 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
698 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
700 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
702 if (r_shadow_buffer_lighttrispvs)
703 Mem_Free(r_shadow_buffer_lighttrispvs);
704 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
705 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
709 void R_Shadow_PrepareShadowMark(int numtris)
711 // make sure shadowmark is big enough for this volume
712 if (maxshadowmark < numtris)
714 maxshadowmark = numtris;
716 Mem_Free(shadowmark);
718 Mem_Free(shadowmarklist);
719 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
720 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
724 // if shadowmarkcount wrapped we clear the array and adjust accordingly
725 if (shadowmarkcount == 0)
728 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
733 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)
736 int outtriangles = 0, outvertices = 0;
739 float ratio, direction[3], projectvector[3];
741 if (projectdirection)
742 VectorScale(projectdirection, projectdistance, projectvector);
744 VectorClear(projectvector);
746 // create the vertices
747 if (projectdirection)
749 for (i = 0;i < numshadowmarktris;i++)
751 element = inelement3i + shadowmarktris[i] * 3;
752 for (j = 0;j < 3;j++)
754 if (vertexupdate[element[j]] != vertexupdatenum)
756 vertexupdate[element[j]] = vertexupdatenum;
757 vertexremap[element[j]] = outvertices;
758 vertex = invertex3f + element[j] * 3;
759 // project one copy of the vertex according to projectvector
760 VectorCopy(vertex, outvertex3f);
761 VectorAdd(vertex, projectvector, (outvertex3f + 3));
770 for (i = 0;i < numshadowmarktris;i++)
772 element = inelement3i + shadowmarktris[i] * 3;
773 for (j = 0;j < 3;j++)
775 if (vertexupdate[element[j]] != vertexupdatenum)
777 vertexupdate[element[j]] = vertexupdatenum;
778 vertexremap[element[j]] = outvertices;
779 vertex = invertex3f + element[j] * 3;
780 // project one copy of the vertex to the sphere radius of the light
781 // (FIXME: would projecting it to the light box be better?)
782 VectorSubtract(vertex, projectorigin, direction);
783 ratio = projectdistance / VectorLength(direction);
784 VectorCopy(vertex, outvertex3f);
785 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
793 if (r_shadow_frontsidecasting.integer)
795 for (i = 0;i < numshadowmarktris;i++)
797 int remappedelement[3];
799 const int *neighbortriangle;
801 markindex = shadowmarktris[i] * 3;
802 element = inelement3i + markindex;
803 neighbortriangle = inneighbor3i + markindex;
804 // output the front and back triangles
805 outelement3i[0] = vertexremap[element[0]];
806 outelement3i[1] = vertexremap[element[1]];
807 outelement3i[2] = vertexremap[element[2]];
808 outelement3i[3] = vertexremap[element[2]] + 1;
809 outelement3i[4] = vertexremap[element[1]] + 1;
810 outelement3i[5] = vertexremap[element[0]] + 1;
814 // output the sides (facing outward from this triangle)
815 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
817 remappedelement[0] = vertexremap[element[0]];
818 remappedelement[1] = vertexremap[element[1]];
819 outelement3i[0] = remappedelement[1];
820 outelement3i[1] = remappedelement[0];
821 outelement3i[2] = remappedelement[0] + 1;
822 outelement3i[3] = remappedelement[1];
823 outelement3i[4] = remappedelement[0] + 1;
824 outelement3i[5] = remappedelement[1] + 1;
829 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
831 remappedelement[1] = vertexremap[element[1]];
832 remappedelement[2] = vertexremap[element[2]];
833 outelement3i[0] = remappedelement[2];
834 outelement3i[1] = remappedelement[1];
835 outelement3i[2] = remappedelement[1] + 1;
836 outelement3i[3] = remappedelement[2];
837 outelement3i[4] = remappedelement[1] + 1;
838 outelement3i[5] = remappedelement[2] + 1;
843 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
845 remappedelement[0] = vertexremap[element[0]];
846 remappedelement[2] = vertexremap[element[2]];
847 outelement3i[0] = remappedelement[0];
848 outelement3i[1] = remappedelement[2];
849 outelement3i[2] = remappedelement[2] + 1;
850 outelement3i[3] = remappedelement[0];
851 outelement3i[4] = remappedelement[2] + 1;
852 outelement3i[5] = remappedelement[0] + 1;
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[2]];
872 outelement3i[1] = vertexremap[element[1]];
873 outelement3i[2] = vertexremap[element[0]];
874 outelement3i[3] = vertexremap[element[0]] + 1;
875 outelement3i[4] = vertexremap[element[1]] + 1;
876 outelement3i[5] = vertexremap[element[2]] + 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[0];
886 outelement3i[1] = remappedelement[1];
887 outelement3i[2] = remappedelement[1] + 1;
888 outelement3i[3] = remappedelement[0];
889 outelement3i[4] = remappedelement[1] + 1;
890 outelement3i[5] = remappedelement[0] + 1;
895 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
897 remappedelement[1] = vertexremap[element[1]];
898 remappedelement[2] = vertexremap[element[2]];
899 outelement3i[0] = remappedelement[1];
900 outelement3i[1] = remappedelement[2];
901 outelement3i[2] = remappedelement[2] + 1;
902 outelement3i[3] = remappedelement[1];
903 outelement3i[4] = remappedelement[2] + 1;
904 outelement3i[5] = remappedelement[1] + 1;
909 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
911 remappedelement[0] = vertexremap[element[0]];
912 remappedelement[2] = vertexremap[element[2]];
913 outelement3i[0] = remappedelement[2];
914 outelement3i[1] = remappedelement[0];
915 outelement3i[2] = remappedelement[0] + 1;
916 outelement3i[3] = remappedelement[2];
917 outelement3i[4] = remappedelement[0] + 1;
918 outelement3i[5] = remappedelement[2] + 1;
926 *outnumvertices = outvertices;
930 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)
933 int outtriangles = 0, outvertices = 0;
936 float ratio, direction[3], projectvector[3];
939 if (projectdirection)
940 VectorScale(projectdirection, projectdistance, projectvector);
942 VectorClear(projectvector);
944 for (i = 0;i < numshadowmarktris;i++)
946 int remappedelement[3];
948 const int *neighbortriangle;
950 markindex = shadowmarktris[i] * 3;
951 neighbortriangle = inneighbor3i + markindex;
952 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
953 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
954 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
955 if (side[0] + side[1] + side[2] == 0)
959 element = inelement3i + markindex;
961 // create the vertices
962 for (j = 0;j < 3;j++)
964 if (side[j] + side[j+1] == 0)
967 if (vertexupdate[k] != vertexupdatenum)
969 vertexupdate[k] = vertexupdatenum;
970 vertexremap[k] = outvertices;
971 vertex = invertex3f + k * 3;
972 VectorCopy(vertex, outvertex3f);
973 if (projectdirection)
975 // project one copy of the vertex according to projectvector
976 VectorAdd(vertex, projectvector, (outvertex3f + 3));
980 // project one copy of the vertex to the sphere radius of the light
981 // (FIXME: would projecting it to the light box be better?)
982 VectorSubtract(vertex, projectorigin, direction);
983 ratio = projectdistance / VectorLength(direction);
984 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
991 // output the sides (facing outward from this triangle)
994 remappedelement[0] = vertexremap[element[0]];
995 remappedelement[1] = vertexremap[element[1]];
996 outelement3i[0] = remappedelement[1];
997 outelement3i[1] = remappedelement[0];
998 outelement3i[2] = remappedelement[0] + 1;
999 outelement3i[3] = remappedelement[1];
1000 outelement3i[4] = remappedelement[0] + 1;
1001 outelement3i[5] = remappedelement[1] + 1;
1008 remappedelement[1] = vertexremap[element[1]];
1009 remappedelement[2] = vertexremap[element[2]];
1010 outelement3i[0] = remappedelement[2];
1011 outelement3i[1] = remappedelement[1];
1012 outelement3i[2] = remappedelement[1] + 1;
1013 outelement3i[3] = remappedelement[2];
1014 outelement3i[4] = remappedelement[1] + 1;
1015 outelement3i[5] = remappedelement[2] + 1;
1022 remappedelement[0] = vertexremap[element[0]];
1023 remappedelement[2] = vertexremap[element[2]];
1024 outelement3i[0] = remappedelement[0];
1025 outelement3i[1] = remappedelement[2];
1026 outelement3i[2] = remappedelement[2] + 1;
1027 outelement3i[3] = remappedelement[0];
1028 outelement3i[4] = remappedelement[2] + 1;
1029 outelement3i[5] = remappedelement[0] + 1;
1036 *outnumvertices = outvertices;
1037 return outtriangles;
1040 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)
1046 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1048 tend = firsttriangle + numtris;
1049 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1051 // surface box entirely inside light box, no box cull
1052 if (projectdirection)
1054 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1056 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1057 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1058 shadowmarklist[numshadowmark++] = t;
1063 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1064 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1065 shadowmarklist[numshadowmark++] = t;
1070 // surface box not entirely inside light box, cull each triangle
1071 if (projectdirection)
1073 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1075 v[0] = invertex3f + e[0] * 3;
1076 v[1] = invertex3f + e[1] * 3;
1077 v[2] = invertex3f + e[2] * 3;
1078 TriangleNormal(v[0], v[1], v[2], normal);
1079 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1080 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1081 shadowmarklist[numshadowmark++] = t;
1086 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1088 v[0] = invertex3f + e[0] * 3;
1089 v[1] = invertex3f + e[1] * 3;
1090 v[2] = invertex3f + e[2] * 3;
1091 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1092 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1093 shadowmarklist[numshadowmark++] = t;
1099 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1104 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1106 // check if the shadow volume intersects the near plane
1108 // a ray between the eye and light origin may intersect the caster,
1109 // indicating that the shadow may touch the eye location, however we must
1110 // test the near plane (a polygon), not merely the eye location, so it is
1111 // easiest to enlarge the caster bounding shape slightly for this.
1117 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)
1119 int i, tris, outverts;
1120 if (projectdistance < 0.1)
1122 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1125 if (!numverts || !nummarktris)
1127 // make sure shadowelements is big enough for this volume
1128 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1129 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1131 if (maxvertexupdate < numverts)
1133 maxvertexupdate = numverts;
1135 Mem_Free(vertexupdate);
1137 Mem_Free(vertexremap);
1138 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1139 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1140 vertexupdatenum = 0;
1143 if (vertexupdatenum == 0)
1145 vertexupdatenum = 1;
1146 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1147 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1150 for (i = 0;i < nummarktris;i++)
1151 shadowmark[marktris[i]] = shadowmarkcount;
1153 if (r_shadow_compilingrtlight)
1155 // if we're compiling an rtlight, capture the mesh
1156 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1157 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1158 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1159 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1163 // decide which type of shadow to generate and set stencil mode
1164 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1165 // generate the sides or a solid volume, depending on type
1166 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1167 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1169 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1170 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1171 r_refdef.stats.lights_shadowtriangles += tris;
1173 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1174 GL_LockArrays(0, outverts);
1175 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1177 // increment stencil if frontface is infront of depthbuffer
1178 GL_CullFace(r_refdef.view.cullface_front);
1179 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1180 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1181 // decrement stencil if backface is infront of depthbuffer
1182 GL_CullFace(r_refdef.view.cullface_back);
1183 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1185 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1187 // decrement stencil if backface is behind depthbuffer
1188 GL_CullFace(r_refdef.view.cullface_front);
1189 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1190 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1191 // increment stencil if frontface is behind depthbuffer
1192 GL_CullFace(r_refdef.view.cullface_back);
1193 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1195 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1196 GL_LockArrays(0, 0);
1201 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)
1203 int i, tris = nummarktris;
1206 if (!numverts || !nummarktris)
1208 // make sure shadowelements is big enough for this mesh
1209 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1210 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1212 // gather up the (sparse) triangles into one array
1213 outelement3i = shadowelements;
1214 for (i = 0;i < nummarktris;i++)
1216 element = elements + marktris[i] * 3;
1217 outelement3i[0] = element[0];
1218 outelement3i[1] = element[1];
1219 outelement3i[2] = element[2];
1223 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1224 r_refdef.stats.lights_shadowtriangles += tris;
1225 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1226 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1229 static void R_Shadow_MakeTextures_MakeCorona(void)
1233 unsigned char pixels[32][32][4];
1234 for (y = 0;y < 32;y++)
1236 dy = (y - 15.5f) * (1.0f / 16.0f);
1237 for (x = 0;x < 32;x++)
1239 dx = (x - 15.5f) * (1.0f / 16.0f);
1240 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1241 a = bound(0, a, 255);
1242 pixels[y][x][0] = a;
1243 pixels[y][x][1] = a;
1244 pixels[y][x][2] = a;
1245 pixels[y][x][3] = 255;
1248 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1251 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1253 float dist = sqrt(x*x+y*y+z*z);
1254 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1255 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1256 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1259 static void R_Shadow_MakeTextures(void)
1262 float intensity, dist;
1264 R_FreeTexturePool(&r_shadow_texturepool);
1265 r_shadow_texturepool = R_AllocTexturePool();
1266 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1267 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1268 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1269 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1270 for (x = 0;x <= ATTENTABLESIZE;x++)
1272 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1273 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1274 r_shadow_attentable[x] = bound(0, intensity, 1);
1276 // 1D gradient texture
1277 for (x = 0;x < ATTEN1DSIZE;x++)
1278 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1279 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);
1280 // 2D circle texture
1281 for (y = 0;y < ATTEN2DSIZE;y++)
1282 for (x = 0;x < ATTEN2DSIZE;x++)
1283 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);
1284 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);
1285 // 3D sphere texture
1286 if (r_shadow_texture3d.integer && gl_texture3d)
1288 for (z = 0;z < ATTEN3DSIZE;z++)
1289 for (y = 0;y < ATTEN3DSIZE;y++)
1290 for (x = 0;x < ATTEN3DSIZE;x++)
1291 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));
1292 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);
1295 r_shadow_attenuation3dtexture = NULL;
1298 R_Shadow_MakeTextures_MakeCorona();
1300 // Editor light sprites
1301 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1302 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1303 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1304 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1305 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1306 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1309 void R_Shadow_ValidateCvars(void)
1311 if (r_shadow_texture3d.integer && !gl_texture3d)
1312 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1313 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1314 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1315 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1316 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1319 void R_Shadow_RenderMode_Begin(void)
1323 R_Shadow_ValidateCvars();
1325 if (!r_shadow_attenuation2dtexture
1326 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1327 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1328 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1329 R_Shadow_MakeTextures();
1332 R_Mesh_ColorPointer(NULL, 0, 0);
1333 R_Mesh_ResetTextureState();
1334 GL_BlendFunc(GL_ONE, GL_ZERO);
1335 GL_DepthRange(0, 1);
1336 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1338 GL_DepthMask(false);
1339 GL_Color(0, 0, 0, 1);
1340 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1342 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1344 if (gl_ext_separatestencil.integer)
1346 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1347 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1349 else if (gl_ext_stenciltwoside.integer)
1351 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1352 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1356 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1357 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1360 if (r_glsl.integer && gl_support_fragment_shader)
1361 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1362 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1363 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1365 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1368 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1369 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1370 r_shadow_drawbuffer = drawbuffer;
1371 r_shadow_readbuffer = readbuffer;
1374 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1376 rsurface.rtlight = rtlight;
1379 void R_Shadow_RenderMode_Reset(void)
1382 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1384 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1386 if (gl_support_ext_framebuffer_object)
1388 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1390 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1391 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1392 R_SetViewport(&r_refdef.view.viewport);
1393 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1394 R_Mesh_ColorPointer(NULL, 0, 0);
1395 R_Mesh_ResetTextureState();
1396 GL_DepthRange(0, 1);
1398 GL_DepthMask(false);
1399 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1400 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1401 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1402 qglStencilMask(~0);CHECKGLERROR
1403 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1404 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1405 GL_CullFace(r_refdef.view.cullface_back);
1406 GL_Color(1, 1, 1, 1);
1407 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1408 GL_BlendFunc(GL_ONE, GL_ZERO);
1409 R_SetupGenericShader(false);
1410 r_shadow_usingshadowmaprect = false;
1411 r_shadow_usingshadowmapcube = false;
1412 r_shadow_usingshadowmap2d = false;
1416 void R_Shadow_ClearStencil(void)
1419 GL_Clear(GL_STENCIL_BUFFER_BIT);
1420 r_refdef.stats.lights_clears++;
1423 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1425 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1426 if (r_shadow_rendermode == mode)
1429 R_Shadow_RenderMode_Reset();
1430 GL_ColorMask(0, 0, 0, 0);
1431 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1432 R_SetupDepthOrShadowShader();
1433 qglDepthFunc(GL_LESS);CHECKGLERROR
1434 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1435 r_shadow_rendermode = mode;
1440 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1441 GL_CullFace(GL_NONE);
1442 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1443 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1445 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1446 GL_CullFace(GL_NONE);
1447 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1448 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1450 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1451 GL_CullFace(GL_NONE);
1452 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1453 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1454 qglStencilMask(~0);CHECKGLERROR
1455 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1456 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1457 qglStencilMask(~0);CHECKGLERROR
1458 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1460 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1461 GL_CullFace(GL_NONE);
1462 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1463 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1464 qglStencilMask(~0);CHECKGLERROR
1465 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1466 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1467 qglStencilMask(~0);CHECKGLERROR
1468 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1473 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1478 float nearclip, farclip, bias;
1479 r_viewport_t viewport;
1481 maxsize = r_shadow_shadowmapmaxsize;
1482 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1484 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1485 r_shadow_shadowmap_texturescale[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1486 r_shadow_shadowmap_texturescale[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1487 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmap_texturescale[2];
1488 r_shadow_shadowmap_parameters[3] = r_shadow_shadowmap_texturescale[3];
1489 if (r_shadow_shadowmode == 1)
1491 // complex unrolled cube approach (more flexible)
1492 if (!r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1493 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", 2, 4, size, r_shadow_shadowmapborder);
1494 if (!r_shadow_shadowmap2dtexture)
1497 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1498 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1499 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1500 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1504 R_Shadow_RenderMode_Reset();
1505 if (r_shadow_shadowmap2dtexture)
1507 // render depth into the fbo, do not render color at all
1508 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1509 qglDrawBuffer(GL_NONE);CHECKGLERROR
1510 qglReadBuffer(GL_NONE);CHECKGLERROR
1511 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1512 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1514 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1515 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1517 R_SetupDepthOrShadowShader();
1521 R_SetupShowDepthShader();
1522 qglClearColor(1,1,1,1);CHECKGLERROR
1524 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1525 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1526 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1527 r_shadow_shadowmap_parameters[0] = (0.5f / 4) * (1.0f - r_shadow_shadowmapborder) / size;
1528 r_shadow_shadowmap_parameters[1] = 1.0f / (3 * 4);
1529 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1531 else if (r_shadow_shadowmode == 2)
1533 // complex unrolled cube approach (more flexible)
1534 if (!r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1535 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", 2, 3, size, r_shadow_shadowmapborder);
1536 if (!r_shadow_shadowmaprectangletexture)
1539 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1540 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1541 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1542 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1546 R_Shadow_RenderMode_Reset();
1547 if (r_shadow_shadowmaprectangletexture)
1549 // render depth into the fbo, do not render color at all
1550 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1551 qglDrawBuffer(GL_NONE);CHECKGLERROR
1552 qglReadBuffer(GL_NONE);CHECKGLERROR
1553 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1554 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1556 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1557 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1559 R_SetupDepthOrShadowShader();
1563 R_SetupShowDepthShader();
1564 qglClearColor(1,1,1,1);CHECKGLERROR
1566 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1567 r_shadow_shadowmap_texturescale[0] = 2*size;
1568 r_shadow_shadowmap_texturescale[1] = 3*size;
1569 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1570 r_shadow_shadowmap_parameters[1] = size;
1571 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1573 else if (r_shadow_shadowmode == 3)
1575 // simple cube approach
1576 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1579 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1580 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1581 for (i = 0;i < 6;i++)
1583 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1584 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
1589 R_Shadow_RenderMode_Reset();
1590 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1592 // render depth into the fbo, do not render color at all
1593 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1594 qglDrawBuffer(GL_NONE);CHECKGLERROR
1595 qglReadBuffer(GL_NONE);CHECKGLERROR
1596 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1597 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1599 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1600 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1602 R_SetupDepthOrShadowShader();
1606 R_SetupShowDepthShader();
1607 qglClearColor(1,1,1,1);CHECKGLERROR
1609 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1610 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1611 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1612 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmap_texturescale[0];
1613 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmap_texturescale[1];
1614 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1617 R_SetViewport(&viewport);
1618 GL_PolygonOffset(0, 0);
1619 GL_CullFace(GL_NONE); // quake is backwards
1620 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1623 qglClearDepth(1);CHECKGLERROR
1626 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1630 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1633 R_Shadow_RenderMode_Reset();
1634 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1637 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1641 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1642 // only draw light where this geometry was already rendered AND the
1643 // stencil is 128 (values other than this mean shadow)
1644 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1646 r_shadow_rendermode = r_shadow_lightingrendermode;
1647 // do global setup needed for the chosen lighting mode
1648 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1650 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1651 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1655 if (r_shadow_shadowmode == 1)
1657 r_shadow_usingshadowmap2d = true;
1658 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1661 else if (r_shadow_shadowmode == 2)
1663 r_shadow_usingshadowmaprect = true;
1664 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1667 else if (r_shadow_shadowmode == 3)
1669 r_shadow_usingshadowmapcube = true;
1670 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1674 if (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect)
1676 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]));
1681 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1682 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1683 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1687 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1690 R_Shadow_RenderMode_Reset();
1691 GL_BlendFunc(GL_ONE, GL_ONE);
1692 GL_DepthRange(0, 1);
1693 GL_DepthTest(r_showshadowvolumes.integer < 2);
1694 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1695 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1696 GL_CullFace(GL_NONE);
1697 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1700 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1703 R_Shadow_RenderMode_Reset();
1704 GL_BlendFunc(GL_ONE, GL_ONE);
1705 GL_DepthRange(0, 1);
1706 GL_DepthTest(r_showlighting.integer < 2);
1707 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1710 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1714 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1715 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1717 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1720 void R_Shadow_RenderMode_End(void)
1723 R_Shadow_RenderMode_Reset();
1724 R_Shadow_RenderMode_ActiveLight(NULL);
1726 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1727 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1730 int bboxedges[12][2] =
1749 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1751 int i, ix1, iy1, ix2, iy2;
1752 float x1, y1, x2, y2;
1754 float vertex[20][3];
1763 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1764 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1765 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1766 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1768 if (!r_shadow_scissor.integer)
1771 // if view is inside the light box, just say yes it's visible
1772 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1775 x1 = y1 = x2 = y2 = 0;
1777 // transform all corners that are infront of the nearclip plane
1778 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1779 plane4f[3] = r_refdef.view.frustum[4].dist;
1781 for (i = 0;i < 8;i++)
1783 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1784 dist[i] = DotProduct4(corner[i], plane4f);
1785 sign[i] = dist[i] > 0;
1788 VectorCopy(corner[i], vertex[numvertices]);
1792 // if some points are behind the nearclip, add clipped edge points to make
1793 // sure that the scissor boundary is complete
1794 if (numvertices > 0 && numvertices < 8)
1796 // add clipped edge points
1797 for (i = 0;i < 12;i++)
1799 j = bboxedges[i][0];
1800 k = bboxedges[i][1];
1801 if (sign[j] != sign[k])
1803 f = dist[j] / (dist[j] - dist[k]);
1804 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1810 // if we have no points to check, the light is behind the view plane
1814 // if we have some points to transform, check what screen area is covered
1815 x1 = y1 = x2 = y2 = 0;
1817 //Con_Printf("%i vertices to transform...\n", numvertices);
1818 for (i = 0;i < numvertices;i++)
1820 VectorCopy(vertex[i], v);
1821 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1822 //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]);
1825 if (x1 > v2[0]) x1 = v2[0];
1826 if (x2 < v2[0]) x2 = v2[0];
1827 if (y1 > v2[1]) y1 = v2[1];
1828 if (y2 < v2[1]) y2 = v2[1];
1837 // now convert the scissor rectangle to integer screen coordinates
1838 ix1 = (int)(x1 - 1.0f);
1839 iy1 = vid.height - (int)(y2 - 1.0f);
1840 ix2 = (int)(x2 + 1.0f);
1841 iy2 = vid.height - (int)(y1 + 1.0f);
1842 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1844 // clamp it to the screen
1845 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1846 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1847 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1848 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1850 // if it is inside out, it's not visible
1851 if (ix2 <= ix1 || iy2 <= iy1)
1854 // the light area is visible, set up the scissor rectangle
1855 r_shadow_lightscissor[0] = ix1;
1856 r_shadow_lightscissor[1] = iy1;
1857 r_shadow_lightscissor[2] = ix2 - ix1;
1858 r_shadow_lightscissor[3] = iy2 - iy1;
1860 r_refdef.stats.lights_scissored++;
1864 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1866 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1867 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1868 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1869 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1870 if (r_textureunits.integer >= 3)
1872 if (VectorLength2(diffusecolor) > 0)
1874 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1876 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1877 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1878 if ((dot = DotProduct(n, v)) < 0)
1880 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1881 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1884 VectorCopy(ambientcolor, color4f);
1885 if (r_refdef.fogenabled)
1888 f = FogPoint_Model(vertex3f);
1889 VectorScale(color4f, f, color4f);
1896 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1898 VectorCopy(ambientcolor, color4f);
1899 if (r_refdef.fogenabled)
1902 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1903 f = FogPoint_Model(vertex3f);
1904 VectorScale(color4f, f, color4f);
1910 else if (r_textureunits.integer >= 2)
1912 if (VectorLength2(diffusecolor) > 0)
1914 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1916 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1917 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1919 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1920 if ((dot = DotProduct(n, v)) < 0)
1922 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1923 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1924 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1925 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1929 color4f[0] = ambientcolor[0] * distintensity;
1930 color4f[1] = ambientcolor[1] * distintensity;
1931 color4f[2] = ambientcolor[2] * distintensity;
1933 if (r_refdef.fogenabled)
1936 f = FogPoint_Model(vertex3f);
1937 VectorScale(color4f, f, color4f);
1941 VectorClear(color4f);
1947 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1949 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1950 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1952 color4f[0] = ambientcolor[0] * distintensity;
1953 color4f[1] = ambientcolor[1] * distintensity;
1954 color4f[2] = ambientcolor[2] * distintensity;
1955 if (r_refdef.fogenabled)
1958 f = FogPoint_Model(vertex3f);
1959 VectorScale(color4f, f, color4f);
1963 VectorClear(color4f);
1970 if (VectorLength2(diffusecolor) > 0)
1972 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1974 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1975 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1977 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1978 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1979 if ((dot = DotProduct(n, v)) < 0)
1981 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1982 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1983 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1984 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1988 color4f[0] = ambientcolor[0] * distintensity;
1989 color4f[1] = ambientcolor[1] * distintensity;
1990 color4f[2] = ambientcolor[2] * distintensity;
1992 if (r_refdef.fogenabled)
1995 f = FogPoint_Model(vertex3f);
1996 VectorScale(color4f, f, color4f);
2000 VectorClear(color4f);
2006 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2008 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2009 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2011 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2012 color4f[0] = ambientcolor[0] * distintensity;
2013 color4f[1] = ambientcolor[1] * distintensity;
2014 color4f[2] = ambientcolor[2] * distintensity;
2015 if (r_refdef.fogenabled)
2018 f = FogPoint_Model(vertex3f);
2019 VectorScale(color4f, f, color4f);
2023 VectorClear(color4f);
2030 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2032 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2035 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2036 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2037 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2038 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2039 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2041 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2043 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2044 // the cubemap normalizes this for us
2045 out3f[0] = DotProduct(svector3f, lightdir);
2046 out3f[1] = DotProduct(tvector3f, lightdir);
2047 out3f[2] = DotProduct(normal3f, lightdir);
2051 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2054 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2055 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2056 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2057 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2058 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2059 float lightdir[3], eyedir[3], halfdir[3];
2060 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2062 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2063 VectorNormalize(lightdir);
2064 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2065 VectorNormalize(eyedir);
2066 VectorAdd(lightdir, eyedir, halfdir);
2067 // the cubemap normalizes this for us
2068 out3f[0] = DotProduct(svector3f, halfdir);
2069 out3f[1] = DotProduct(tvector3f, halfdir);
2070 out3f[2] = DotProduct(normal3f, halfdir);
2074 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)
2076 // used to display how many times a surface is lit for level design purposes
2077 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2080 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)
2082 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2083 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2084 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2085 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2087 R_Mesh_ColorPointer(NULL, 0, 0);
2088 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2089 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2090 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2091 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2092 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2093 if (rsurface.texture->backgroundcurrentskinframe)
2095 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2096 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2097 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2098 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2100 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2101 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2102 if(rsurface.texture->colormapping)
2104 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2105 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2107 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2108 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2109 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2110 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2111 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2112 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2114 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2116 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2117 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2119 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2123 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)
2125 // shared final code for all the dot3 layers
2127 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2128 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2130 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2131 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2135 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)
2138 // colorscale accounts for how much we multiply the brightness
2141 // mult is how many times the final pass of the lighting will be
2142 // performed to get more brightness than otherwise possible.
2144 // Limit mult to 64 for sanity sake.
2146 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2148 // 3 3D combine path (Geforce3, Radeon 8500)
2149 memset(&m, 0, sizeof(m));
2150 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2151 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2152 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2153 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2154 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2155 m.tex[1] = R_GetTexture(basetexture);
2156 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2157 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2158 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2159 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2160 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2161 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2162 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2163 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2164 m.texmatrix[2] = rsurface.entitytolight;
2165 GL_BlendFunc(GL_ONE, GL_ONE);
2167 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2169 // 2 3D combine path (Geforce3, original Radeon)
2170 memset(&m, 0, sizeof(m));
2171 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2172 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2173 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2174 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2175 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2176 m.tex[1] = R_GetTexture(basetexture);
2177 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2178 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2179 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2180 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2181 GL_BlendFunc(GL_ONE, GL_ONE);
2183 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2185 // 4 2D combine path (Geforce3, Radeon 8500)
2186 memset(&m, 0, sizeof(m));
2187 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2188 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2189 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2190 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2191 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2192 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2193 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2194 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2195 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2196 m.texmatrix[1] = rsurface.entitytoattenuationz;
2197 m.tex[2] = R_GetTexture(basetexture);
2198 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2199 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2200 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2201 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2202 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2204 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2205 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2206 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2207 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2208 m.texmatrix[3] = rsurface.entitytolight;
2210 GL_BlendFunc(GL_ONE, GL_ONE);
2212 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2214 // 3 2D combine path (Geforce3, original Radeon)
2215 memset(&m, 0, sizeof(m));
2216 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2217 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2218 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2219 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2220 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2221 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2222 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2223 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2224 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2225 m.texmatrix[1] = rsurface.entitytoattenuationz;
2226 m.tex[2] = R_GetTexture(basetexture);
2227 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2228 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2229 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2230 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2231 GL_BlendFunc(GL_ONE, GL_ONE);
2235 // 2/2/2 2D combine path (any dot3 card)
2236 memset(&m, 0, sizeof(m));
2237 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2238 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2239 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2240 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2241 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2242 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2243 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2244 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2245 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2246 m.texmatrix[1] = rsurface.entitytoattenuationz;
2247 R_Mesh_TextureState(&m);
2248 GL_ColorMask(0,0,0,1);
2249 GL_BlendFunc(GL_ONE, GL_ZERO);
2250 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2253 memset(&m, 0, sizeof(m));
2254 m.tex[0] = R_GetTexture(basetexture);
2255 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2256 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2258 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2259 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2261 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2262 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2263 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2264 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2265 m.texmatrix[1] = rsurface.entitytolight;
2267 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2269 // this final code is shared
2270 R_Mesh_TextureState(&m);
2271 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);
2274 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)
2277 // colorscale accounts for how much we multiply the brightness
2280 // mult is how many times the final pass of the lighting will be
2281 // performed to get more brightness than otherwise possible.
2283 // Limit mult to 64 for sanity sake.
2285 // generate normalization cubemap texcoords
2286 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2287 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2289 // 3/2 3D combine path (Geforce3, Radeon 8500)
2290 memset(&m, 0, sizeof(m));
2291 m.tex[0] = R_GetTexture(normalmaptexture);
2292 m.texcombinergb[0] = GL_REPLACE;
2293 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2294 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2295 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2296 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2297 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2298 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2299 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2300 m.pointer_texcoord_bufferobject[1] = 0;
2301 m.pointer_texcoord_bufferoffset[1] = 0;
2302 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2303 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2304 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2305 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2306 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2307 R_Mesh_TextureState(&m);
2308 GL_ColorMask(0,0,0,1);
2309 GL_BlendFunc(GL_ONE, GL_ZERO);
2310 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2313 memset(&m, 0, sizeof(m));
2314 m.tex[0] = R_GetTexture(basetexture);
2315 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2316 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2317 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2318 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2319 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2321 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2322 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2323 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2324 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2325 m.texmatrix[1] = rsurface.entitytolight;
2327 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2329 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2331 // 1/2/2 3D combine path (original Radeon)
2332 memset(&m, 0, sizeof(m));
2333 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2334 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2335 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2336 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2337 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2338 R_Mesh_TextureState(&m);
2339 GL_ColorMask(0,0,0,1);
2340 GL_BlendFunc(GL_ONE, GL_ZERO);
2341 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2344 memset(&m, 0, sizeof(m));
2345 m.tex[0] = R_GetTexture(normalmaptexture);
2346 m.texcombinergb[0] = GL_REPLACE;
2347 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2348 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2349 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2350 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2351 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2352 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2353 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2354 m.pointer_texcoord_bufferobject[1] = 0;
2355 m.pointer_texcoord_bufferoffset[1] = 0;
2356 R_Mesh_TextureState(&m);
2357 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2358 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2361 memset(&m, 0, sizeof(m));
2362 m.tex[0] = R_GetTexture(basetexture);
2363 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2364 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2365 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2366 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2367 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2369 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2370 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2371 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2372 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2373 m.texmatrix[1] = rsurface.entitytolight;
2375 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2377 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2379 // 2/2 3D combine path (original Radeon)
2380 memset(&m, 0, sizeof(m));
2381 m.tex[0] = R_GetTexture(normalmaptexture);
2382 m.texcombinergb[0] = GL_REPLACE;
2383 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2384 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2385 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2386 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2387 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2388 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2389 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2390 m.pointer_texcoord_bufferobject[1] = 0;
2391 m.pointer_texcoord_bufferoffset[1] = 0;
2392 R_Mesh_TextureState(&m);
2393 GL_ColorMask(0,0,0,1);
2394 GL_BlendFunc(GL_ONE, GL_ZERO);
2395 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2398 memset(&m, 0, sizeof(m));
2399 m.tex[0] = R_GetTexture(basetexture);
2400 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2401 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2402 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2403 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2404 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2405 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2406 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2407 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2408 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2409 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2411 else if (r_textureunits.integer >= 4)
2413 // 4/2 2D combine path (Geforce3, Radeon 8500)
2414 memset(&m, 0, sizeof(m));
2415 m.tex[0] = R_GetTexture(normalmaptexture);
2416 m.texcombinergb[0] = GL_REPLACE;
2417 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2418 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2419 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2420 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2421 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2422 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2423 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2424 m.pointer_texcoord_bufferobject[1] = 0;
2425 m.pointer_texcoord_bufferoffset[1] = 0;
2426 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2427 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2428 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2429 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2430 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2431 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2432 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2433 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2434 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2435 m.texmatrix[3] = rsurface.entitytoattenuationz;
2436 R_Mesh_TextureState(&m);
2437 GL_ColorMask(0,0,0,1);
2438 GL_BlendFunc(GL_ONE, GL_ZERO);
2439 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2442 memset(&m, 0, sizeof(m));
2443 m.tex[0] = R_GetTexture(basetexture);
2444 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2445 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2446 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2447 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2448 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2450 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2451 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2452 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2453 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2454 m.texmatrix[1] = rsurface.entitytolight;
2456 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2460 // 2/2/2 2D combine path (any dot3 card)
2461 memset(&m, 0, sizeof(m));
2462 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2463 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2464 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2465 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2466 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2467 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2468 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2469 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2470 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2471 m.texmatrix[1] = rsurface.entitytoattenuationz;
2472 R_Mesh_TextureState(&m);
2473 GL_ColorMask(0,0,0,1);
2474 GL_BlendFunc(GL_ONE, GL_ZERO);
2475 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2478 memset(&m, 0, sizeof(m));
2479 m.tex[0] = R_GetTexture(normalmaptexture);
2480 m.texcombinergb[0] = GL_REPLACE;
2481 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2482 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2483 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2484 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2485 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2486 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2487 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2488 m.pointer_texcoord_bufferobject[1] = 0;
2489 m.pointer_texcoord_bufferoffset[1] = 0;
2490 R_Mesh_TextureState(&m);
2491 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2492 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2495 memset(&m, 0, sizeof(m));
2496 m.tex[0] = R_GetTexture(basetexture);
2497 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2498 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2499 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2500 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2501 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2503 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2504 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2505 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2506 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2507 m.texmatrix[1] = rsurface.entitytolight;
2509 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2511 // this final code is shared
2512 R_Mesh_TextureState(&m);
2513 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);
2516 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)
2518 float glossexponent;
2520 // FIXME: detect blendsquare!
2521 //if (!gl_support_blendsquare)
2524 // generate normalization cubemap texcoords
2525 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2526 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2528 // 2/0/0/1/2 3D combine blendsquare path
2529 memset(&m, 0, sizeof(m));
2530 m.tex[0] = R_GetTexture(normalmaptexture);
2531 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2532 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2533 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2534 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2535 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2536 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2537 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2538 m.pointer_texcoord_bufferobject[1] = 0;
2539 m.pointer_texcoord_bufferoffset[1] = 0;
2540 R_Mesh_TextureState(&m);
2541 GL_ColorMask(0,0,0,1);
2542 // this squares the result
2543 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2544 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2546 // second and third pass
2547 R_Mesh_ResetTextureState();
2548 // square alpha in framebuffer a few times to make it shiny
2549 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2550 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2551 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2554 memset(&m, 0, sizeof(m));
2555 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2556 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2557 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2558 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2559 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2560 R_Mesh_TextureState(&m);
2561 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2562 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2565 memset(&m, 0, sizeof(m));
2566 m.tex[0] = R_GetTexture(glosstexture);
2567 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2568 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2569 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2570 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2571 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2573 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2574 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2575 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2576 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2577 m.texmatrix[1] = rsurface.entitytolight;
2579 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2581 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2583 // 2/0/0/2 3D combine blendsquare path
2584 memset(&m, 0, sizeof(m));
2585 m.tex[0] = R_GetTexture(normalmaptexture);
2586 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2587 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2588 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2589 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2590 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2591 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2592 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2593 m.pointer_texcoord_bufferobject[1] = 0;
2594 m.pointer_texcoord_bufferoffset[1] = 0;
2595 R_Mesh_TextureState(&m);
2596 GL_ColorMask(0,0,0,1);
2597 // this squares the result
2598 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2599 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2601 // second and third pass
2602 R_Mesh_ResetTextureState();
2603 // square alpha in framebuffer a few times to make it shiny
2604 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2605 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2606 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2609 memset(&m, 0, sizeof(m));
2610 m.tex[0] = R_GetTexture(glosstexture);
2611 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2612 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2613 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2614 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2615 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2616 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2617 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2618 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2619 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2620 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2624 // 2/0/0/2/2 2D combine blendsquare path
2625 memset(&m, 0, sizeof(m));
2626 m.tex[0] = R_GetTexture(normalmaptexture);
2627 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2628 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2629 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2630 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2631 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2632 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2633 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2634 m.pointer_texcoord_bufferobject[1] = 0;
2635 m.pointer_texcoord_bufferoffset[1] = 0;
2636 R_Mesh_TextureState(&m);
2637 GL_ColorMask(0,0,0,1);
2638 // this squares the result
2639 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2640 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2642 // second and third pass
2643 R_Mesh_ResetTextureState();
2644 // square alpha in framebuffer a few times to make it shiny
2645 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2646 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2647 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2650 memset(&m, 0, sizeof(m));
2651 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2652 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2653 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2654 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2655 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2656 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2657 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2658 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2659 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2660 m.texmatrix[1] = rsurface.entitytoattenuationz;
2661 R_Mesh_TextureState(&m);
2662 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2663 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2666 memset(&m, 0, sizeof(m));
2667 m.tex[0] = R_GetTexture(glosstexture);
2668 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2669 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2670 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2671 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2672 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2674 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2675 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2676 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2677 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2678 m.texmatrix[1] = rsurface.entitytolight;
2680 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2682 // this final code is shared
2683 R_Mesh_TextureState(&m);
2684 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);
2687 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)
2689 // ARB path (any Geforce, any Radeon)
2690 qboolean doambient = ambientscale > 0;
2691 qboolean dodiffuse = diffusescale > 0;
2692 qboolean dospecular = specularscale > 0;
2693 if (!doambient && !dodiffuse && !dospecular)
2695 R_Mesh_ColorPointer(NULL, 0, 0);
2697 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2699 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2703 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2705 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2710 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2712 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2715 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2718 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2725 int newnumtriangles;
2729 int maxtriangles = 4096;
2730 int newelements[4096*3];
2731 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2732 for (renders = 0;renders < 64;renders++)
2737 newnumtriangles = 0;
2739 // due to low fillrate on the cards this vertex lighting path is
2740 // designed for, we manually cull all triangles that do not
2741 // contain a lit vertex
2742 // this builds batches of triangles from multiple surfaces and
2743 // renders them at once
2744 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2746 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2748 if (newnumtriangles)
2750 newfirstvertex = min(newfirstvertex, e[0]);
2751 newlastvertex = max(newlastvertex, e[0]);
2755 newfirstvertex = e[0];
2756 newlastvertex = e[0];
2758 newfirstvertex = min(newfirstvertex, e[1]);
2759 newlastvertex = max(newlastvertex, e[1]);
2760 newfirstvertex = min(newfirstvertex, e[2]);
2761 newlastvertex = max(newlastvertex, e[2]);
2767 if (newnumtriangles >= maxtriangles)
2769 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2770 newnumtriangles = 0;
2776 if (newnumtriangles >= 1)
2778 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2781 // if we couldn't find any lit triangles, exit early
2784 // now reduce the intensity for the next overbright pass
2785 // we have to clamp to 0 here incase the drivers have improper
2786 // handling of negative colors
2787 // (some old drivers even have improper handling of >1 color)
2789 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2791 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2793 c[0] = max(0, c[0] - 1);
2794 c[1] = max(0, c[1] - 1);
2795 c[2] = max(0, c[2] - 1);
2807 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)
2809 // OpenGL 1.1 path (anything)
2810 float ambientcolorbase[3], diffusecolorbase[3];
2811 float ambientcolorpants[3], diffusecolorpants[3];
2812 float ambientcolorshirt[3], diffusecolorshirt[3];
2814 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2815 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2816 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2817 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2818 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2819 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2820 memset(&m, 0, sizeof(m));
2821 m.tex[0] = R_GetTexture(basetexture);
2822 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2823 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2824 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2825 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2826 if (r_textureunits.integer >= 2)
2829 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2830 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2831 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2832 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2833 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2834 if (r_textureunits.integer >= 3)
2836 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2837 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2838 m.texmatrix[2] = rsurface.entitytoattenuationz;
2839 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2840 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2841 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2844 R_Mesh_TextureState(&m);
2845 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2846 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2849 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2850 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2854 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2855 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2859 extern cvar_t gl_lightmaps;
2860 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)
2862 float ambientscale, diffusescale, specularscale;
2863 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2865 // calculate colors to render this texture with
2866 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2867 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2868 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2869 ambientscale = rsurface.rtlight->ambientscale;
2870 diffusescale = rsurface.rtlight->diffusescale;
2871 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2872 if (!r_shadow_usenormalmap.integer)
2874 ambientscale += 1.0f * diffusescale;
2878 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2880 RSurf_SetupDepthAndCulling();
2881 nmap = rsurface.texture->currentskinframe->nmap;
2882 if (gl_lightmaps.integer)
2883 nmap = r_texture_blanknormalmap;
2884 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2886 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2887 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2890 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2891 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2892 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2895 VectorClear(lightcolorpants);
2898 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2899 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2900 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2903 VectorClear(lightcolorshirt);
2904 switch (r_shadow_rendermode)
2906 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2907 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2908 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);
2910 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2911 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);
2913 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2914 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);
2916 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2917 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);
2920 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2926 switch (r_shadow_rendermode)
2928 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2929 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2930 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);
2932 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2933 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);
2935 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2936 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);
2938 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2939 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);
2942 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2948 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)
2950 matrix4x4_t tempmatrix = *matrix;
2951 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2953 // if this light has been compiled before, free the associated data
2954 R_RTLight_Uncompile(rtlight);
2956 // clear it completely to avoid any lingering data
2957 memset(rtlight, 0, sizeof(*rtlight));
2959 // copy the properties
2960 rtlight->matrix_lighttoworld = tempmatrix;
2961 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2962 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2963 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2964 VectorCopy(color, rtlight->color);
2965 rtlight->cubemapname[0] = 0;
2966 if (cubemapname && cubemapname[0])
2967 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2968 rtlight->shadow = shadow;
2969 rtlight->corona = corona;
2970 rtlight->style = style;
2971 rtlight->isstatic = isstatic;
2972 rtlight->coronasizescale = coronasizescale;
2973 rtlight->ambientscale = ambientscale;
2974 rtlight->diffusescale = diffusescale;
2975 rtlight->specularscale = specularscale;
2976 rtlight->flags = flags;
2978 // compute derived data
2979 //rtlight->cullradius = rtlight->radius;
2980 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2981 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2982 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2983 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2984 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2985 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2986 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2989 // compiles rtlight geometry
2990 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2991 void R_RTLight_Compile(rtlight_t *rtlight)
2994 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2995 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2996 entity_render_t *ent = r_refdef.scene.worldentity;
2997 dp_model_t *model = r_refdef.scene.worldmodel;
2998 unsigned char *data;
3001 // compile the light
3002 rtlight->compiled = true;
3003 rtlight->static_numleafs = 0;
3004 rtlight->static_numleafpvsbytes = 0;
3005 rtlight->static_leaflist = NULL;
3006 rtlight->static_leafpvs = NULL;
3007 rtlight->static_numsurfaces = 0;
3008 rtlight->static_surfacelist = NULL;
3009 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3010 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3011 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3012 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3013 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3014 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3016 if (model && model->GetLightInfo)
3018 // this variable must be set for the CompileShadowVolume code
3019 r_shadow_compilingrtlight = rtlight;
3020 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);
3021 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);
3022 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3023 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3024 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3025 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3026 rtlight->static_numsurfaces = numsurfaces;
3027 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3028 rtlight->static_numleafs = numleafs;
3029 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3030 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3031 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3032 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3033 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3034 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3035 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3036 if (rtlight->static_numsurfaces)
3037 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3038 if (rtlight->static_numleafs)
3039 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3040 if (rtlight->static_numleafpvsbytes)
3041 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3042 if (rtlight->static_numshadowtrispvsbytes)
3043 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3044 if (rtlight->static_numlighttrispvsbytes)
3045 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3046 if (model->CompileShadowVolume && rtlight->shadow)
3047 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3048 // now we're done compiling the rtlight
3049 r_shadow_compilingrtlight = NULL;
3053 // use smallest available cullradius - box radius or light radius
3054 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3055 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3057 shadowzpasstris = 0;
3058 if (rtlight->static_meshchain_shadow_zpass)
3059 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3060 shadowzpasstris += mesh->numtriangles;
3062 shadowzfailtris = 0;
3063 if (rtlight->static_meshchain_shadow_zfail)
3064 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3065 shadowzfailtris += mesh->numtriangles;
3068 if (rtlight->static_numlighttrispvsbytes)
3069 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3070 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3074 if (rtlight->static_numlighttrispvsbytes)
3075 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3076 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3079 if (developer.integer >= 10)
3080 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);
3083 void R_RTLight_Uncompile(rtlight_t *rtlight)
3085 if (rtlight->compiled)
3087 if (rtlight->static_meshchain_shadow_zpass)
3088 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3089 rtlight->static_meshchain_shadow_zpass = NULL;
3090 if (rtlight->static_meshchain_shadow_zfail)
3091 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3092 rtlight->static_meshchain_shadow_zfail = NULL;
3093 // these allocations are grouped
3094 if (rtlight->static_surfacelist)
3095 Mem_Free(rtlight->static_surfacelist);
3096 rtlight->static_numleafs = 0;
3097 rtlight->static_numleafpvsbytes = 0;
3098 rtlight->static_leaflist = NULL;
3099 rtlight->static_leafpvs = NULL;
3100 rtlight->static_numsurfaces = 0;
3101 rtlight->static_surfacelist = NULL;
3102 rtlight->static_numshadowtrispvsbytes = 0;
3103 rtlight->static_shadowtrispvs = NULL;
3104 rtlight->static_numlighttrispvsbytes = 0;
3105 rtlight->static_lighttrispvs = NULL;
3106 rtlight->compiled = false;
3110 void R_Shadow_UncompileWorldLights(void)
3114 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3115 for (lightindex = 0;lightindex < range;lightindex++)
3117 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3120 R_RTLight_Uncompile(&light->rtlight);
3124 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3128 // reset the count of frustum planes
3129 // see rsurface.rtlight_frustumplanes definition for how much this array
3131 rsurface.rtlight_numfrustumplanes = 0;
3133 // haven't implemented a culling path for ortho rendering
3134 if (!r_refdef.view.useperspective)
3136 // check if the light is on screen and copy the 4 planes if it is
3137 for (i = 0;i < 4;i++)
3138 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3141 for (i = 0;i < 4;i++)
3142 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3147 // generate a deformed frustum that includes the light origin, this is
3148 // used to cull shadow casting surfaces that can not possibly cast a
3149 // shadow onto the visible light-receiving surfaces, which can be a
3152 // if the light origin is onscreen the result will be 4 planes exactly
3153 // if the light origin is offscreen on only one axis the result will
3154 // be exactly 5 planes (split-side case)
3155 // if the light origin is offscreen on two axes the result will be
3156 // exactly 4 planes (stretched corner case)
3157 for (i = 0;i < 4;i++)
3159 // quickly reject standard frustum planes that put the light
3160 // origin outside the frustum
3161 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3164 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3166 // if all the standard frustum planes were accepted, the light is onscreen
3167 // otherwise we need to generate some more planes below...
3168 if (rsurface.rtlight_numfrustumplanes < 4)
3170 // at least one of the stock frustum planes failed, so we need to
3171 // create one or two custom planes to enclose the light origin
3172 for (i = 0;i < 4;i++)
3174 // create a plane using the view origin and light origin, and a
3175 // single point from the frustum corner set
3176 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3177 VectorNormalize(plane.normal);
3178 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3179 // see if this plane is backwards and flip it if so
3180 for (j = 0;j < 4;j++)
3181 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3185 VectorNegate(plane.normal, plane.normal);
3187 // flipped plane, test again to see if it is now valid
3188 for (j = 0;j < 4;j++)
3189 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3191 // if the plane is still not valid, then it is dividing the
3192 // frustum and has to be rejected
3196 // we have created a valid plane, compute extra info
3197 PlaneClassify(&plane);
3199 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3201 // if we've found 5 frustum planes then we have constructed a
3202 // proper split-side case and do not need to keep searching for
3203 // planes to enclose the light origin
3204 if (rsurface.rtlight_numfrustumplanes == 5)
3212 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3214 plane = rsurface.rtlight_frustumplanes[i];
3215 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));
3220 // now add the light-space box planes if the light box is rotated, as any
3221 // caster outside the oriented light box is irrelevant (even if it passed
3222 // the worldspace light box, which is axial)
3223 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3225 for (i = 0;i < 6;i++)
3229 v[i >> 1] = (i & 1) ? -1 : 1;
3230 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3231 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3232 plane.dist = VectorNormalizeLength(plane.normal);
3233 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3234 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3240 // add the world-space reduced box planes
3241 for (i = 0;i < 6;i++)
3243 VectorClear(plane.normal);
3244 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3245 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3246 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3255 // reduce all plane distances to tightly fit the rtlight cull box, which
3257 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3258 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3259 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3260 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3261 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3262 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3263 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3264 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3265 oldnum = rsurface.rtlight_numfrustumplanes;
3266 rsurface.rtlight_numfrustumplanes = 0;
3267 for (j = 0;j < oldnum;j++)
3269 // find the nearest point on the box to this plane
3270 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3271 for (i = 1;i < 8;i++)
3273 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3274 if (bestdist > dist)
3277 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);
3278 // if the nearest point is near or behind the plane, we want this
3279 // plane, otherwise the plane is useless as it won't cull anything
3280 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3282 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3283 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3290 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3295 int surfacelistindex;
3296 msurface_t *surface;
3298 RSurf_ActiveWorldEntity();
3299 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3301 if (r_refdef.scene.worldentity->model)
3302 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3303 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3307 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3310 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3311 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3312 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3313 for (;mesh;mesh = mesh->next)
3315 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3316 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3317 GL_LockArrays(0, mesh->numverts);
3318 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3320 // increment stencil if frontface is infront of depthbuffer
3321 GL_CullFace(r_refdef.view.cullface_back);
3322 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3323 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3324 // decrement stencil if backface is infront of depthbuffer
3325 GL_CullFace(r_refdef.view.cullface_front);
3326 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3328 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3330 // decrement stencil if backface is behind depthbuffer
3331 GL_CullFace(r_refdef.view.cullface_front);
3332 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3333 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3334 // increment stencil if frontface is behind depthbuffer
3335 GL_CullFace(r_refdef.view.cullface_back);
3336 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3338 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3339 GL_LockArrays(0, 0);
3343 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3345 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3346 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3348 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3349 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3350 if (CHECKPVSBIT(trispvs, t))
3351 shadowmarklist[numshadowmark++] = t;
3353 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);
3355 else if (numsurfaces)
3356 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3358 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3361 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3363 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3364 vec_t relativeshadowradius;
3365 RSurf_ActiveModelEntity(ent, false, false);
3366 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3367 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3368 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3369 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3370 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3371 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3372 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3373 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3374 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3375 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3377 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3378 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3381 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3383 // set up properties for rendering light onto this entity
3384 RSurf_ActiveModelEntity(ent, true, true);
3385 GL_AlphaTest(false);
3386 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3387 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3388 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3389 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3390 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3391 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3394 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3396 if (!r_refdef.scene.worldmodel->DrawLight)
3399 // set up properties for rendering light onto this entity
3400 RSurf_ActiveWorldEntity();
3401 GL_AlphaTest(false);
3402 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3403 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3404 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3405 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3406 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3407 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3409 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3411 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3414 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3416 dp_model_t *model = ent->model;
3417 if (!model->DrawLight)
3420 R_Shadow_SetupEntityLight(ent);
3422 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3424 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3428 {{ 0, 0, 0}, "px", true, true, true},
3429 {{ 0, 90, 0}, "py", false, true, false},
3430 {{ 0, 180, 0}, "nx", false, false, true},
3431 {{ 0, 270, 0}, "ny", true, false, false},
3432 {{-90, 180, 0}, "pz", false, false, true},
3433 {{ 90, 180, 0}, "nz", false, false, true}
3436 static const double shadowviewmat16[6][4][4] =
3476 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3480 int numleafs, numsurfaces;
3481 int *leaflist, *surfacelist;
3482 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3483 int numlightentities;
3484 int numlightentities_noselfshadow;
3485 int numshadowentities;
3486 int numshadowentities_noselfshadow;
3487 static entity_render_t *lightentities[MAX_EDICTS];
3488 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3489 static entity_render_t *shadowentities[MAX_EDICTS];
3490 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3491 vec3_t nearestpoint;
3493 qboolean castshadows;
3496 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3497 // skip lights that are basically invisible (color 0 0 0)
3498 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3501 // loading is done before visibility checks because loading should happen
3502 // all at once at the start of a level, not when it stalls gameplay.
3503 // (especially important to benchmarks)
3505 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3506 R_RTLight_Compile(rtlight);
3508 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3510 // look up the light style value at this time
3511 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3512 VectorScale(rtlight->color, f, rtlight->currentcolor);
3514 if (rtlight->selected)
3516 f = 2 + sin(realtime * M_PI * 4.0);
3517 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3521 // if lightstyle is currently off, don't draw the light
3522 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3525 // if the light box is offscreen, skip it
3526 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3529 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3530 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3532 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3534 // compiled light, world available and can receive realtime lighting
3535 // retrieve leaf information
3536 numleafs = rtlight->static_numleafs;
3537 leaflist = rtlight->static_leaflist;
3538 leafpvs = rtlight->static_leafpvs;
3539 numsurfaces = rtlight->static_numsurfaces;
3540 surfacelist = rtlight->static_surfacelist;
3541 shadowtrispvs = rtlight->static_shadowtrispvs;
3542 lighttrispvs = rtlight->static_lighttrispvs;
3544 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3546 // dynamic light, world available and can receive realtime lighting
3547 // calculate lit surfaces and leafs
3548 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);
3549 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);
3550 leaflist = r_shadow_buffer_leaflist;
3551 leafpvs = r_shadow_buffer_leafpvs;
3552 surfacelist = r_shadow_buffer_surfacelist;
3553 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3554 lighttrispvs = r_shadow_buffer_lighttrispvs;
3555 // if the reduced leaf bounds are offscreen, skip it
3556 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3567 shadowtrispvs = NULL;
3568 lighttrispvs = NULL;
3570 // check if light is illuminating any visible leafs
3573 for (i = 0;i < numleafs;i++)
3574 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3579 // set up a scissor rectangle for this light
3580 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3583 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3585 // make a list of lit entities and shadow casting entities
3586 numlightentities = 0;
3587 numlightentities_noselfshadow = 0;
3588 numshadowentities = 0;
3589 numshadowentities_noselfshadow = 0;
3590 // add dynamic entities that are lit by the light
3591 if (r_drawentities.integer)
3593 for (i = 0;i < r_refdef.scene.numentities;i++)
3596 entity_render_t *ent = r_refdef.scene.entities[i];
3598 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3600 // skip the object entirely if it is not within the valid
3601 // shadow-casting region (which includes the lit region)
3602 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3604 if (!(model = ent->model))
3606 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3608 // this entity wants to receive light, is visible, and is
3609 // inside the light box
3610 // TODO: check if the surfaces in the model can receive light
3611 // so now check if it's in a leaf seen by the light
3612 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))
3614 if (ent->flags & RENDER_NOSELFSHADOW)
3615 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3617 lightentities[numlightentities++] = ent;
3618 // since it is lit, it probably also casts a shadow...
3619 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3620 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3621 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3623 // note: exterior models without the RENDER_NOSELFSHADOW
3624 // flag still create a RENDER_NOSELFSHADOW shadow but
3625 // are lit normally, this means that they are
3626 // self-shadowing but do not shadow other
3627 // RENDER_NOSELFSHADOW entities such as the gun
3628 // (very weird, but keeps the player shadow off the gun)
3629 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3630 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3632 shadowentities[numshadowentities++] = ent;
3635 else if (ent->flags & RENDER_SHADOW)
3637 // this entity is not receiving light, but may still need to
3639 // TODO: check if the surfaces in the model can cast shadow
3640 // now check if it is in a leaf seen by the light
3641 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))
3643 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3644 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3645 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3647 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3648 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3650 shadowentities[numshadowentities++] = ent;
3656 // return if there's nothing at all to light
3657 if (!numlightentities && !numsurfaces)
3660 // don't let sound skip if going slow
3661 if (r_refdef.scene.extraupdate)
3664 // make this the active rtlight for rendering purposes
3665 R_Shadow_RenderMode_ActiveLight(rtlight);
3666 // count this light in the r_speeds
3667 r_refdef.stats.lights++;
3669 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3671 // optionally draw visible shape of the shadow volumes
3672 // for performance analysis by level designers
3673 R_Shadow_RenderMode_VisibleShadowVolumes();
3675 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3676 for (i = 0;i < numshadowentities;i++)
3677 R_Shadow_DrawEntityShadow(shadowentities[i]);
3678 for (i = 0;i < numshadowentities_noselfshadow;i++)
3679 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3682 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3684 // optionally draw the illuminated areas
3685 // for performance analysis by level designers
3686 R_Shadow_RenderMode_VisibleLighting(false, false);
3688 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3689 for (i = 0;i < numlightentities;i++)
3690 R_Shadow_DrawEntityLight(lightentities[i]);
3691 for (i = 0;i < numlightentities_noselfshadow;i++)
3692 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3695 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3697 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3698 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3699 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3700 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3701 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3702 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3704 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3709 r_shadow_shadowmaplod = 0;
3710 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3711 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3712 r_shadow_shadowmaplod = i;
3714 size = bound(1, r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod, 2048);
3716 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3718 // render shadow casters into 6 sided depth texture
3719 for (side = 0;side < 6;side++)
3721 R_Shadow_RenderMode_ShadowMap(side, true, size);
3723 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3724 for (i = 0;i < numshadowentities;i++)
3725 R_Shadow_DrawEntityShadow(shadowentities[i]);
3728 if (numlightentities_noselfshadow)
3730 // render lighting using the depth texture as shadowmap
3731 // draw lighting in the unmasked areas
3732 R_Shadow_RenderMode_Lighting(false, false, true);
3733 for (i = 0;i < numlightentities_noselfshadow;i++)
3734 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3737 // render shadow casters into 6 sided depth texture
3738 for (side = 0;side < 6;side++)
3740 R_Shadow_RenderMode_ShadowMap(side, false, size);
3741 for (i = 0;i < numshadowentities_noselfshadow;i++)
3742 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3745 // render lighting using the depth texture as shadowmap
3746 // draw lighting in the unmasked areas
3747 R_Shadow_RenderMode_Lighting(false, false, true);
3748 // draw lighting in the unmasked areas
3750 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3751 for (i = 0;i < numlightentities;i++)
3752 R_Shadow_DrawEntityLight(lightentities[i]);
3754 else if (castshadows && gl_stencil)
3756 // draw stencil shadow volumes to mask off pixels that are in shadow
3757 // so that they won't receive lighting
3758 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3759 R_Shadow_ClearStencil();
3761 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3762 for (i = 0;i < numshadowentities;i++)
3763 R_Shadow_DrawEntityShadow(shadowentities[i]);
3764 if (numlightentities_noselfshadow)
3766 // draw lighting in the unmasked areas
3767 R_Shadow_RenderMode_Lighting(true, false, false);
3768 for (i = 0;i < numlightentities_noselfshadow;i++)
3769 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3771 // optionally draw the illuminated areas
3772 // for performance analysis by level designers
3773 if (r_showlighting.integer && r_refdef.view.showdebug)
3775 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3776 for (i = 0;i < numlightentities_noselfshadow;i++)
3777 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3780 for (i = 0;i < numshadowentities_noselfshadow;i++)
3781 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3783 if (numsurfaces + numlightentities)
3785 // draw lighting in the unmasked areas
3786 R_Shadow_RenderMode_Lighting(true, false, false);
3788 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3789 for (i = 0;i < numlightentities;i++)
3790 R_Shadow_DrawEntityLight(lightentities[i]);
3795 if (numsurfaces + numlightentities)
3797 // draw lighting in the unmasked areas
3798 R_Shadow_RenderMode_Lighting(false, false, false);
3800 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3801 for (i = 0;i < numlightentities;i++)
3802 R_Shadow_DrawEntityLight(lightentities[i]);
3803 for (i = 0;i < numlightentities_noselfshadow;i++)
3804 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3809 void R_Shadow_DrawLightSprites(void);
3810 void R_ShadowVolumeLighting(qboolean visible)
3818 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3819 R_Shadow_FreeShadowMaps();
3821 if (r_editlights.integer)
3822 R_Shadow_DrawLightSprites();
3824 R_Shadow_RenderMode_Begin();
3826 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3827 if (r_shadow_debuglight.integer >= 0)
3829 lightindex = r_shadow_debuglight.integer;
3830 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3831 if (light && (light->flags & flag))
3832 R_DrawRTLight(&light->rtlight, visible);
3836 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3837 for (lightindex = 0;lightindex < range;lightindex++)
3839 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3840 if (light && (light->flags & flag))
3841 R_DrawRTLight(&light->rtlight, visible);
3844 if (r_refdef.scene.rtdlight)
3845 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3846 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3848 R_Shadow_RenderMode_End();
3851 extern const float r_screenvertex3f[12];
3852 extern void R_SetupView(qboolean allowwaterclippingplane);
3853 extern void R_ResetViewRendering3D(void);
3854 extern void R_ResetViewRendering2D(void);
3855 extern cvar_t r_shadows;
3856 extern cvar_t r_shadows_darken;
3857 extern cvar_t r_shadows_drawafterrtlighting;
3858 extern cvar_t r_shadows_castfrombmodels;
3859 extern cvar_t r_shadows_throwdistance;
3860 extern cvar_t r_shadows_throwdirection;
3861 void R_DrawModelShadows(void)
3864 float relativethrowdistance;
3865 entity_render_t *ent;
3866 vec3_t relativelightorigin;
3867 vec3_t relativelightdirection;
3868 vec3_t relativeshadowmins, relativeshadowmaxs;
3869 vec3_t tmp, shadowdir;
3871 if (!r_drawentities.integer || !gl_stencil)
3875 R_ResetViewRendering3D();
3876 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3877 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3878 R_Shadow_RenderMode_Begin();
3879 R_Shadow_RenderMode_ActiveLight(NULL);
3880 r_shadow_lightscissor[0] = r_refdef.view.x;
3881 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3882 r_shadow_lightscissor[2] = r_refdef.view.width;
3883 r_shadow_lightscissor[3] = r_refdef.view.height;
3884 R_Shadow_RenderMode_StencilShadowVolumes(false);
3887 if (r_shadows.integer == 2)
3889 Math_atov(r_shadows_throwdirection.string, shadowdir);
3890 VectorNormalize(shadowdir);
3893 R_Shadow_ClearStencil();
3895 for (i = 0;i < r_refdef.scene.numentities;i++)
3897 ent = r_refdef.scene.entities[i];
3899 // cast shadows from anything of the map (submodels are optional)
3900 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3902 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3903 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3904 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3905 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3906 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3909 if(ent->entitynumber != 0)
3911 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3912 int entnum, entnum2, recursion;
3913 entnum = entnum2 = ent->entitynumber;
3914 for(recursion = 32; recursion > 0; --recursion)
3916 entnum2 = cl.entities[entnum].state_current.tagentity;
3917 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3922 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3924 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3925 // transform into modelspace of OUR entity
3926 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3927 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3930 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3933 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3936 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3937 RSurf_ActiveModelEntity(ent, false, false);
3938 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3939 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3943 // not really the right mode, but this will disable any silly stencil features
3944 R_Shadow_RenderMode_End();
3946 // set up ortho view for rendering this pass
3947 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3948 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3949 //GL_ScissorTest(true);
3950 //R_Mesh_Matrix(&identitymatrix);
3951 //R_Mesh_ResetTextureState();
3952 R_ResetViewRendering2D();
3953 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3954 R_Mesh_ColorPointer(NULL, 0, 0);
3955 R_SetupGenericShader(false);
3957 // set up a darkening blend on shadowed areas
3958 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3959 //GL_DepthRange(0, 1);
3960 //GL_DepthTest(false);
3961 //GL_DepthMask(false);
3962 //GL_PolygonOffset(0, 0);CHECKGLERROR
3963 GL_Color(0, 0, 0, r_shadows_darken.value);
3964 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3965 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3966 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3967 qglStencilMask(~0);CHECKGLERROR
3968 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3969 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3971 // apply the blend to the shadowed areas
3972 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3974 // restore the viewport
3975 R_SetViewport(&r_refdef.view.viewport);
3977 // restore other state to normal
3978 //R_Shadow_RenderMode_End();
3981 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3984 vec3_t centerorigin;
3985 // if it's too close, skip it
3986 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3988 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3991 if (usequery && r_numqueries + 2 <= r_maxqueries)
3993 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3994 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3995 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
3998 // 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
3999 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4000 qglDepthFunc(GL_ALWAYS);
4001 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);
4002 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4003 qglDepthFunc(GL_LEQUAL);
4004 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4005 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);
4006 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4009 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4012 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4015 GLint allpixels = 0, visiblepixels = 0;
4016 // now we have to check the query result
4017 if (rtlight->corona_queryindex_visiblepixels)
4020 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4021 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4023 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4024 if (visiblepixels < 1 || allpixels < 1)
4026 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4027 cscale *= rtlight->corona_visibility;
4031 // FIXME: these traces should scan all render entities instead of cl.world
4032 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4035 VectorScale(rtlight->color, cscale, color);
4036 if (VectorLength(color) > (1.0f / 256.0f))
4037 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);
4040 void R_DrawCoronas(void)
4048 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4050 if (r_waterstate.renderingscene)
4052 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4053 R_Mesh_Matrix(&identitymatrix);
4055 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4057 // check occlusion of coronas
4058 // use GL_ARB_occlusion_query if available
4059 // otherwise use raytraces
4061 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4064 GL_ColorMask(0,0,0,0);
4065 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4066 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4069 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4070 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4072 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4076 for (lightindex = 0;lightindex < range;lightindex++)
4078 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4081 rtlight = &light->rtlight;
4082 rtlight->corona_visibility = 0;
4083 rtlight->corona_queryindex_visiblepixels = 0;
4084 rtlight->corona_queryindex_allpixels = 0;
4085 if (!(rtlight->flags & flag))
4087 if (rtlight->corona <= 0)
4089 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4091 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4093 for (i = 0;i < r_refdef.scene.numlights;i++)
4095 rtlight = r_refdef.scene.lights[i];
4096 rtlight->corona_visibility = 0;
4097 rtlight->corona_queryindex_visiblepixels = 0;
4098 rtlight->corona_queryindex_allpixels = 0;
4099 if (!(rtlight->flags & flag))
4101 if (rtlight->corona <= 0)
4103 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4106 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4108 // now draw the coronas using the query data for intensity info
4109 for (lightindex = 0;lightindex < range;lightindex++)
4111 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4114 rtlight = &light->rtlight;
4115 if (rtlight->corona_visibility <= 0)
4117 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4119 for (i = 0;i < r_refdef.scene.numlights;i++)
4121 rtlight = r_refdef.scene.lights[i];
4122 if (rtlight->corona_visibility <= 0)
4124 if (gl_flashblend.integer)
4125 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4127 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4133 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4134 typedef struct suffixinfo_s
4137 qboolean flipx, flipy, flipdiagonal;
4140 static suffixinfo_t suffix[3][6] =
4143 {"px", false, false, false},
4144 {"nx", false, false, false},
4145 {"py", false, false, false},
4146 {"ny", false, false, false},
4147 {"pz", false, false, false},
4148 {"nz", false, false, false}
4151 {"posx", false, false, false},
4152 {"negx", false, false, false},
4153 {"posy", false, false, false},
4154 {"negy", false, false, false},
4155 {"posz", false, false, false},
4156 {"negz", false, false, false}
4159 {"rt", true, false, true},
4160 {"lf", false, true, true},
4161 {"ft", true, true, false},
4162 {"bk", false, false, false},
4163 {"up", true, false, true},
4164 {"dn", true, false, true}
4168 static int componentorder[4] = {0, 1, 2, 3};
4170 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4172 int i, j, cubemapsize;
4173 unsigned char *cubemappixels, *image_buffer;
4174 rtexture_t *cubemaptexture;
4176 // must start 0 so the first loadimagepixels has no requested width/height
4178 cubemappixels = NULL;
4179 cubemaptexture = NULL;
4180 // keep trying different suffix groups (posx, px, rt) until one loads
4181 for (j = 0;j < 3 && !cubemappixels;j++)
4183 // load the 6 images in the suffix group
4184 for (i = 0;i < 6;i++)
4186 // generate an image name based on the base and and suffix
4187 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4189 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4191 // an image loaded, make sure width and height are equal
4192 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4194 // if this is the first image to load successfully, allocate the cubemap memory
4195 if (!cubemappixels && image_width >= 1)
4197 cubemapsize = image_width;
4198 // note this clears to black, so unavailable sides are black
4199 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4201 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4203 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);
4206 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4208 Mem_Free(image_buffer);
4212 // if a cubemap loaded, upload it
4215 if (developer_loading.integer)
4216 Con_Printf("loading cubemap \"%s\"\n", basename);
4218 if (!r_shadow_filters_texturepool)
4219 r_shadow_filters_texturepool = R_AllocTexturePool();
4220 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4221 Mem_Free(cubemappixels);
4225 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4226 if (developer_loading.integer)
4228 Con_Printf("(tried tried images ");
4229 for (j = 0;j < 3;j++)
4230 for (i = 0;i < 6;i++)
4231 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4232 Con_Print(" and was unable to find any of them).\n");
4235 return cubemaptexture;
4238 rtexture_t *R_Shadow_Cubemap(const char *basename)
4241 for (i = 0;i < numcubemaps;i++)
4242 if (!strcasecmp(cubemaps[i].basename, basename))
4243 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4244 if (i >= MAX_CUBEMAPS)
4245 return r_texture_whitecube;
4247 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4248 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4249 return cubemaps[i].texture;
4252 void R_Shadow_FreeCubemaps(void)
4255 for (i = 0;i < numcubemaps;i++)
4257 if (developer_loading.integer)
4258 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4259 if (cubemaps[i].texture)
4260 R_FreeTexture(cubemaps[i].texture);
4264 R_FreeTexturePool(&r_shadow_filters_texturepool);
4267 dlight_t *R_Shadow_NewWorldLight(void)
4269 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4272 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)
4275 // validate parameters
4276 if (style < 0 || style >= MAX_LIGHTSTYLES)
4278 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4284 // copy to light properties
4285 VectorCopy(origin, light->origin);
4286 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4287 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4288 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4289 light->color[0] = max(color[0], 0);
4290 light->color[1] = max(color[1], 0);
4291 light->color[2] = max(color[2], 0);
4292 light->radius = max(radius, 0);
4293 light->style = style;
4294 light->shadow = shadowenable;
4295 light->corona = corona;
4296 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4297 light->coronasizescale = coronasizescale;
4298 light->ambientscale = ambientscale;
4299 light->diffusescale = diffusescale;
4300 light->specularscale = specularscale;
4301 light->flags = flags;
4303 // update renderable light data
4304 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4305 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);
4308 void R_Shadow_FreeWorldLight(dlight_t *light)
4310 if (r_shadow_selectedlight == light)
4311 r_shadow_selectedlight = NULL;
4312 R_RTLight_Uncompile(&light->rtlight);
4313 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4316 void R_Shadow_ClearWorldLights(void)
4320 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4321 for (lightindex = 0;lightindex < range;lightindex++)
4323 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4325 R_Shadow_FreeWorldLight(light);
4327 r_shadow_selectedlight = NULL;
4328 R_Shadow_FreeCubemaps();
4331 void R_Shadow_SelectLight(dlight_t *light)
4333 if (r_shadow_selectedlight)
4334 r_shadow_selectedlight->selected = false;
4335 r_shadow_selectedlight = light;
4336 if (r_shadow_selectedlight)
4337 r_shadow_selectedlight->selected = true;
4340 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4342 // this is never batched (there can be only one)
4343 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);
4346 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4353 // this is never batched (due to the ent parameter changing every time)
4354 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4355 const dlight_t *light = (dlight_t *)ent;
4358 VectorScale(light->color, intensity, spritecolor);
4359 if (VectorLength(spritecolor) < 0.1732f)
4360 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4361 if (VectorLength(spritecolor) > 1.0f)
4362 VectorNormalize(spritecolor);
4364 // draw light sprite
4365 if (light->cubemapname[0] && !light->shadow)
4366 pic = r_editlights_sprcubemapnoshadowlight;
4367 else if (light->cubemapname[0])
4368 pic = r_editlights_sprcubemaplight;
4369 else if (!light->shadow)
4370 pic = r_editlights_sprnoshadowlight;
4372 pic = r_editlights_sprlight;
4373 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);
4374 // draw selection sprite if light is selected
4375 if (light->selected)
4376 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);
4377 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4380 void R_Shadow_DrawLightSprites(void)
4384 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4385 for (lightindex = 0;lightindex < range;lightindex++)
4387 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4389 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4391 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4394 void R_Shadow_SelectLightInView(void)
4396 float bestrating, rating, temp[3];
4400 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4403 for (lightindex = 0;lightindex < range;lightindex++)
4405 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4408 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4409 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4412 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4413 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)
4415 bestrating = rating;
4420 R_Shadow_SelectLight(best);
4423 void R_Shadow_LoadWorldLights(void)
4425 int n, a, style, shadow, flags;
4426 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4427 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4428 if (cl.worldmodel == NULL)
4430 Con_Print("No map loaded.\n");
4433 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4434 strlcat (name, ".rtlights", sizeof (name));
4435 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4445 for (;COM_Parse(t, true) && strcmp(
4446 if (COM_Parse(t, true))
4448 if (com_token[0] == '!')
4451 origin[0] = atof(com_token+1);
4454 origin[0] = atof(com_token);
4459 while (*s && *s != '\n' && *s != '\r')
4465 // check for modifier flags
4472 #if _MSC_VER >= 1400
4473 #define sscanf sscanf_s
4475 cubemapname[sizeof(cubemapname)-1] = 0;
4476 #if MAX_QPATH != 128
4477 #error update this code if MAX_QPATH changes
4479 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
4480 #if _MSC_VER >= 1400
4481 , sizeof(cubemapname)
4483 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4486 flags = LIGHTFLAG_REALTIMEMODE;
4494 coronasizescale = 0.25f;
4496 VectorClear(angles);
4499 if (a < 9 || !strcmp(cubemapname, "\"\""))
4501 // remove quotes on cubemapname
4502 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4505 namelen = strlen(cubemapname) - 2;
4506 memmove(cubemapname, cubemapname + 1, namelen);
4507 cubemapname[namelen] = '\0';
4511 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);
4514 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4522 Con_Printf("invalid rtlights file \"%s\"\n", name);
4523 Mem_Free(lightsstring);
4527 void R_Shadow_SaveWorldLights(void)
4531 size_t bufchars, bufmaxchars;
4533 char name[MAX_QPATH];
4534 char line[MAX_INPUTLINE];
4535 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4536 // I hate lines which are 3 times my screen size :( --blub
4539 if (cl.worldmodel == NULL)
4541 Con_Print("No map loaded.\n");
4544 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4545 strlcat (name, ".rtlights", sizeof (name));
4546 bufchars = bufmaxchars = 0;
4548 for (lightindex = 0;lightindex < range;lightindex++)
4550 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4553 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4554 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);
4555 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4556 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]);
4558 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);
4559 if (bufchars + strlen(line) > bufmaxchars)
4561 bufmaxchars = bufchars + strlen(line) + 2048;
4563 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4567 memcpy(buf, oldbuf, bufchars);
4573 memcpy(buf + bufchars, line, strlen(line));
4574 bufchars += strlen(line);
4578 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4583 void R_Shadow_LoadLightsFile(void)
4586 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4587 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4588 if (cl.worldmodel == NULL)
4590 Con_Print("No map loaded.\n");
4593 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4594 strlcat (name, ".lights", sizeof (name));
4595 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4603 while (*s && *s != '\n' && *s != '\r')
4609 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);
4613 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);
4616 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4617 radius = bound(15, radius, 4096);
4618 VectorScale(color, (2.0f / (8388608.0f)), color);
4619 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4627 Con_Printf("invalid lights file \"%s\"\n", name);
4628 Mem_Free(lightsstring);
4632 // tyrlite/hmap2 light types in the delay field
4633 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4635 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4637 int entnum, style, islight, skin, pflags, effects, type, n;
4640 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4641 char key[256], value[MAX_INPUTLINE];
4643 if (cl.worldmodel == NULL)
4645 Con_Print("No map loaded.\n");
4648 // try to load a .ent file first
4649 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4650 strlcat (key, ".ent", sizeof (key));
4651 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4652 // and if that is not found, fall back to the bsp file entity string
4654 data = cl.worldmodel->brush.entities;
4657 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4659 type = LIGHTTYPE_MINUSX;
4660 origin[0] = origin[1] = origin[2] = 0;
4661 originhack[0] = originhack[1] = originhack[2] = 0;
4662 angles[0] = angles[1] = angles[2] = 0;
4663 color[0] = color[1] = color[2] = 1;
4664 light[0] = light[1] = light[2] = 1;light[3] = 300;
4665 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4675 if (!COM_ParseToken_Simple(&data, false, false))
4677 if (com_token[0] == '}')
4678 break; // end of entity
4679 if (com_token[0] == '_')
4680 strlcpy(key, com_token + 1, sizeof(key));
4682 strlcpy(key, com_token, sizeof(key));
4683 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4684 key[strlen(key)-1] = 0;
4685 if (!COM_ParseToken_Simple(&data, false, false))
4687 strlcpy(value, com_token, sizeof(value));
4689 // now that we have the key pair worked out...
4690 if (!strcmp("light", key))
4692 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4696 light[0] = vec[0] * (1.0f / 256.0f);
4697 light[1] = vec[0] * (1.0f / 256.0f);
4698 light[2] = vec[0] * (1.0f / 256.0f);
4704 light[0] = vec[0] * (1.0f / 255.0f);
4705 light[1] = vec[1] * (1.0f / 255.0f);
4706 light[2] = vec[2] * (1.0f / 255.0f);
4710 else if (!strcmp("delay", key))
4712 else if (!strcmp("origin", key))
4713 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4714 else if (!strcmp("angle", key))
4715 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4716 else if (!strcmp("angles", key))
4717 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4718 else if (!strcmp("color", key))
4719 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4720 else if (!strcmp("wait", key))
4721 fadescale = atof(value);
4722 else if (!strcmp("classname", key))
4724 if (!strncmp(value, "light", 5))
4727 if (!strcmp(value, "light_fluoro"))
4732 overridecolor[0] = 1;
4733 overridecolor[1] = 1;
4734 overridecolor[2] = 1;
4736 if (!strcmp(value, "light_fluorospark"))
4741 overridecolor[0] = 1;
4742 overridecolor[1] = 1;
4743 overridecolor[2] = 1;
4745 if (!strcmp(value, "light_globe"))
4750 overridecolor[0] = 1;
4751 overridecolor[1] = 0.8;
4752 overridecolor[2] = 0.4;
4754 if (!strcmp(value, "light_flame_large_yellow"))
4759 overridecolor[0] = 1;
4760 overridecolor[1] = 0.5;
4761 overridecolor[2] = 0.1;
4763 if (!strcmp(value, "light_flame_small_yellow"))
4768 overridecolor[0] = 1;
4769 overridecolor[1] = 0.5;
4770 overridecolor[2] = 0.1;
4772 if (!strcmp(value, "light_torch_small_white"))
4777 overridecolor[0] = 1;
4778 overridecolor[1] = 0.5;
4779 overridecolor[2] = 0.1;
4781 if (!strcmp(value, "light_torch_small_walltorch"))
4786 overridecolor[0] = 1;
4787 overridecolor[1] = 0.5;
4788 overridecolor[2] = 0.1;
4792 else if (!strcmp("style", key))
4793 style = atoi(value);
4794 else if (!strcmp("skin", key))
4795 skin = (int)atof(value);
4796 else if (!strcmp("pflags", key))
4797 pflags = (int)atof(value);
4798 else if (!strcmp("effects", key))
4799 effects = (int)atof(value);
4800 else if (cl.worldmodel->type == mod_brushq3)
4802 if (!strcmp("scale", key))
4803 lightscale = atof(value);
4804 if (!strcmp("fade", key))
4805 fadescale = atof(value);
4810 if (lightscale <= 0)
4814 if (color[0] == color[1] && color[0] == color[2])
4816 color[0] *= overridecolor[0];
4817 color[1] *= overridecolor[1];
4818 color[2] *= overridecolor[2];
4820 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4821 color[0] = color[0] * light[0];
4822 color[1] = color[1] * light[1];
4823 color[2] = color[2] * light[2];
4826 case LIGHTTYPE_MINUSX:
4828 case LIGHTTYPE_RECIPX:
4830 VectorScale(color, (1.0f / 16.0f), color);
4832 case LIGHTTYPE_RECIPXX:
4834 VectorScale(color, (1.0f / 16.0f), color);
4837 case LIGHTTYPE_NONE:
4841 case LIGHTTYPE_MINUSXX:
4844 VectorAdd(origin, originhack, origin);
4846 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);
4849 Mem_Free(entfiledata);
4853 void R_Shadow_SetCursorLocationForView(void)
4856 vec3_t dest, endpos;
4858 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4859 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4860 if (trace.fraction < 1)
4862 dist = trace.fraction * r_editlights_cursordistance.value;
4863 push = r_editlights_cursorpushback.value;
4867 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4868 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4872 VectorClear( endpos );
4874 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4875 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4876 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4879 void R_Shadow_UpdateWorldLightSelection(void)
4881 if (r_editlights.integer)
4883 R_Shadow_SetCursorLocationForView();
4884 R_Shadow_SelectLightInView();
4887 R_Shadow_SelectLight(NULL);
4890 void R_Shadow_EditLights_Clear_f(void)
4892 R_Shadow_ClearWorldLights();
4895 void R_Shadow_EditLights_Reload_f(void)
4899 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4900 R_Shadow_ClearWorldLights();
4901 R_Shadow_LoadWorldLights();
4902 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4904 R_Shadow_LoadLightsFile();
4905 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4906 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4910 void R_Shadow_EditLights_Save_f(void)
4914 R_Shadow_SaveWorldLights();
4917 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4919 R_Shadow_ClearWorldLights();
4920 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4923 void R_Shadow_EditLights_ImportLightsFile_f(void)
4925 R_Shadow_ClearWorldLights();
4926 R_Shadow_LoadLightsFile();
4929 void R_Shadow_EditLights_Spawn_f(void)
4932 if (!r_editlights.integer)
4934 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4937 if (Cmd_Argc() != 1)
4939 Con_Print("r_editlights_spawn does not take parameters\n");
4942 color[0] = color[1] = color[2] = 1;
4943 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4946 void R_Shadow_EditLights_Edit_f(void)
4948 vec3_t origin, angles, color;
4949 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4950 int style, shadows, flags, normalmode, realtimemode;
4951 char cubemapname[MAX_INPUTLINE];
4952 if (!r_editlights.integer)
4954 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4957 if (!r_shadow_selectedlight)
4959 Con_Print("No selected light.\n");
4962 VectorCopy(r_shadow_selectedlight->origin, origin);
4963 VectorCopy(r_shadow_selectedlight->angles, angles);
4964 VectorCopy(r_shadow_selectedlight->color, color);
4965 radius = r_shadow_selectedlight->radius;
4966 style = r_shadow_selectedlight->style;
4967 if (r_shadow_selectedlight->cubemapname)
4968 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4971 shadows = r_shadow_selectedlight->shadow;
4972 corona = r_shadow_selectedlight->corona;
4973 coronasizescale = r_shadow_selectedlight->coronasizescale;
4974 ambientscale = r_shadow_selectedlight->ambientscale;
4975 diffusescale = r_shadow_selectedlight->diffusescale;
4976 specularscale = r_shadow_selectedlight->specularscale;
4977 flags = r_shadow_selectedlight->flags;
4978 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4979 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4980 if (!strcmp(Cmd_Argv(1), "origin"))
4982 if (Cmd_Argc() != 5)
4984 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4987 origin[0] = atof(Cmd_Argv(2));
4988 origin[1] = atof(Cmd_Argv(3));
4989 origin[2] = atof(Cmd_Argv(4));
4991 else if (!strcmp(Cmd_Argv(1), "originx"))
4993 if (Cmd_Argc() != 3)
4995 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4998 origin[0] = atof(Cmd_Argv(2));
5000 else if (!strcmp(Cmd_Argv(1), "originy"))
5002 if (Cmd_Argc() != 3)
5004 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5007 origin[1] = atof(Cmd_Argv(2));
5009 else if (!strcmp(Cmd_Argv(1), "originz"))
5011 if (Cmd_Argc() != 3)
5013 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5016 origin[2] = atof(Cmd_Argv(2));
5018 else if (!strcmp(Cmd_Argv(1), "move"))
5020 if (Cmd_Argc() != 5)
5022 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5025 origin[0] += atof(Cmd_Argv(2));
5026 origin[1] += atof(Cmd_Argv(3));
5027 origin[2] += atof(Cmd_Argv(4));
5029 else if (!strcmp(Cmd_Argv(1), "movex"))
5031 if (Cmd_Argc() != 3)
5033 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5036 origin[0] += atof(Cmd_Argv(2));
5038 else if (!strcmp(Cmd_Argv(1), "movey"))
5040 if (Cmd_Argc() != 3)
5042 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5045 origin[1] += atof(Cmd_Argv(2));
5047 else if (!strcmp(Cmd_Argv(1), "movez"))
5049 if (Cmd_Argc() != 3)
5051 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5054 origin[2] += atof(Cmd_Argv(2));
5056 else if (!strcmp(Cmd_Argv(1), "angles"))
5058 if (Cmd_Argc() != 5)
5060 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5063 angles[0] = atof(Cmd_Argv(2));
5064 angles[1] = atof(Cmd_Argv(3));
5065 angles[2] = atof(Cmd_Argv(4));
5067 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5069 if (Cmd_Argc() != 3)
5071 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5074 angles[0] = atof(Cmd_Argv(2));
5076 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5078 if (Cmd_Argc() != 3)
5080 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5083 angles[1] = atof(Cmd_Argv(2));
5085 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5087 if (Cmd_Argc() != 3)
5089 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5092 angles[2] = atof(Cmd_Argv(2));
5094 else if (!strcmp(Cmd_Argv(1), "color"))
5096 if (Cmd_Argc() != 5)
5098 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5101 color[0] = atof(Cmd_Argv(2));
5102 color[1] = atof(Cmd_Argv(3));
5103 color[2] = atof(Cmd_Argv(4));
5105 else if (!strcmp(Cmd_Argv(1), "radius"))
5107 if (Cmd_Argc() != 3)
5109 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5112 radius = atof(Cmd_Argv(2));
5114 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5116 if (Cmd_Argc() == 3)
5118 double scale = atof(Cmd_Argv(2));
5125 if (Cmd_Argc() != 5)
5127 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5130 color[0] *= atof(Cmd_Argv(2));
5131 color[1] *= atof(Cmd_Argv(3));
5132 color[2] *= atof(Cmd_Argv(4));
5135 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5137 if (Cmd_Argc() != 3)
5139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5142 radius *= atof(Cmd_Argv(2));
5144 else if (!strcmp(Cmd_Argv(1), "style"))
5146 if (Cmd_Argc() != 3)
5148 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5151 style = atoi(Cmd_Argv(2));
5153 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5157 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5160 if (Cmd_Argc() == 3)
5161 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5165 else if (!strcmp(Cmd_Argv(1), "shadows"))
5167 if (Cmd_Argc() != 3)
5169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5172 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5174 else if (!strcmp(Cmd_Argv(1), "corona"))
5176 if (Cmd_Argc() != 3)
5178 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5181 corona = atof(Cmd_Argv(2));
5183 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5185 if (Cmd_Argc() != 3)
5187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5190 coronasizescale = atof(Cmd_Argv(2));
5192 else if (!strcmp(Cmd_Argv(1), "ambient"))
5194 if (Cmd_Argc() != 3)
5196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5199 ambientscale = atof(Cmd_Argv(2));
5201 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5203 if (Cmd_Argc() != 3)
5205 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5208 diffusescale = atof(Cmd_Argv(2));
5210 else if (!strcmp(Cmd_Argv(1), "specular"))
5212 if (Cmd_Argc() != 3)
5214 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5217 specularscale = atof(Cmd_Argv(2));
5219 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5221 if (Cmd_Argc() != 3)
5223 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5226 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5228 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5230 if (Cmd_Argc() != 3)
5232 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5235 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5239 Con_Print("usage: r_editlights_edit [property] [value]\n");
5240 Con_Print("Selected light's properties:\n");
5241 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5242 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5243 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5244 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5245 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5246 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5247 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5248 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5249 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5250 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5251 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5252 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5253 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5254 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5257 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5258 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5261 void R_Shadow_EditLights_EditAll_f(void)
5267 if (!r_editlights.integer)
5269 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5273 // EditLights doesn't seem to have a "remove" command or something so:
5274 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5275 for (lightindex = 0;lightindex < range;lightindex++)
5277 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5280 R_Shadow_SelectLight(light);
5281 R_Shadow_EditLights_Edit_f();
5285 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5287 int lightnumber, lightcount;
5288 size_t lightindex, range;
5292 if (!r_editlights.integer)
5294 x = vid_conwidth.value - 240;
5296 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5299 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5300 for (lightindex = 0;lightindex < range;lightindex++)
5302 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5305 if (light == r_shadow_selectedlight)
5306 lightnumber = lightindex;
5309 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;
5310 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;
5312 if (r_shadow_selectedlight == NULL)
5314 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;
5315 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;
5316 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;
5317 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;
5318 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;
5319 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;
5320 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;
5321 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;
5322 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;
5323 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;
5324 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;
5325 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;
5326 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;
5327 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;
5328 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;
5331 void R_Shadow_EditLights_ToggleShadow_f(void)
5333 if (!r_editlights.integer)
5335 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5338 if (!r_shadow_selectedlight)
5340 Con_Print("No selected light.\n");
5343 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);
5346 void R_Shadow_EditLights_ToggleCorona_f(void)
5348 if (!r_editlights.integer)
5350 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5353 if (!r_shadow_selectedlight)
5355 Con_Print("No selected light.\n");
5358 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);
5361 void R_Shadow_EditLights_Remove_f(void)
5363 if (!r_editlights.integer)
5365 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5368 if (!r_shadow_selectedlight)
5370 Con_Print("No selected light.\n");
5373 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5374 r_shadow_selectedlight = NULL;
5377 void R_Shadow_EditLights_Help_f(void)
5380 "Documentation on r_editlights system:\n"
5382 "r_editlights : enable/disable editing mode\n"
5383 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5384 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5385 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5386 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5387 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5389 "r_editlights_help : this help\n"
5390 "r_editlights_clear : remove all lights\n"
5391 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5392 "r_editlights_save : save to .rtlights file\n"
5393 "r_editlights_spawn : create a light with default settings\n"
5394 "r_editlights_edit command : edit selected light - more documentation below\n"
5395 "r_editlights_remove : remove selected light\n"
5396 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5397 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5398 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5400 "origin x y z : set light location\n"
5401 "originx x: set x component of light location\n"
5402 "originy y: set y component of light location\n"
5403 "originz z: set z component of light location\n"
5404 "move x y z : adjust light location\n"
5405 "movex x: adjust x component of light location\n"
5406 "movey y: adjust y component of light location\n"
5407 "movez z: adjust z component of light location\n"
5408 "angles x y z : set light angles\n"
5409 "anglesx x: set x component of light angles\n"
5410 "anglesy y: set y component of light angles\n"
5411 "anglesz z: set z component of light angles\n"
5412 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5413 "radius radius : set radius (size) of light\n"
5414 "colorscale grey : multiply color of light (1 does nothing)\n"
5415 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5416 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5417 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5418 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5419 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5420 "shadows 1/0 : turn on/off shadows\n"
5421 "corona n : set corona intensity\n"
5422 "coronasize n : set corona size (0-1)\n"
5423 "ambient n : set ambient intensity (0-1)\n"
5424 "diffuse n : set diffuse intensity (0-1)\n"
5425 "specular n : set specular intensity (0-1)\n"
5426 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5427 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5428 "<nothing> : print light properties to console\n"
5432 void R_Shadow_EditLights_CopyInfo_f(void)
5434 if (!r_editlights.integer)
5436 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5439 if (!r_shadow_selectedlight)
5441 Con_Print("No selected light.\n");
5444 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5445 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5446 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5447 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5448 if (r_shadow_selectedlight->cubemapname)
5449 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5451 r_shadow_bufferlight.cubemapname[0] = 0;
5452 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5453 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5454 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5455 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5456 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5457 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5458 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5461 void R_Shadow_EditLights_PasteInfo_f(void)
5463 if (!r_editlights.integer)
5465 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5468 if (!r_shadow_selectedlight)
5470 Con_Print("No selected light.\n");
5473 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);
5476 void R_Shadow_EditLights_Init(void)
5478 Cvar_RegisterVariable(&r_editlights);
5479 Cvar_RegisterVariable(&r_editlights_cursordistance);
5480 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5481 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5482 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5483 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5484 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5485 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5486 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)");
5487 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5488 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5489 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5490 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)");
5491 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5492 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5493 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5494 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5495 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5496 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5497 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)");
5503 =============================================================================
5507 =============================================================================
5510 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5512 VectorClear(diffusecolor);
5513 VectorClear(diffusenormal);
5515 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5517 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5518 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5521 VectorSet(ambientcolor, 1, 1, 1);
5528 for (i = 0;i < r_refdef.scene.numlights;i++)
5530 light = r_refdef.scene.lights[i];
5531 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5532 f = 1 - VectorLength2(v);
5533 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5534 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);