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_bias;
175 float r_shadow_shadowmap_texturescale[2];
176 float r_shadow_shadowmap_parameters[4];
177 int r_shadow_drawbuffer;
178 int r_shadow_readbuffer;
179 GLuint r_shadow_fborectangle;
180 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
181 GLuint r_shadow_fbo2d;
182 int r_shadow_shadowmode;
183 int r_shadow_shadowmapmaxsize;
184 int r_shadow_lightscissor[4];
186 int maxshadowtriangles;
189 int maxshadowvertices;
190 float *shadowvertex3f;
203 int r_shadow_buffer_numleafpvsbytes;
204 unsigned char *r_shadow_buffer_visitingleafpvs;
205 unsigned char *r_shadow_buffer_leafpvs;
206 int *r_shadow_buffer_leaflist;
208 int r_shadow_buffer_numsurfacepvsbytes;
209 unsigned char *r_shadow_buffer_surfacepvs;
210 int *r_shadow_buffer_surfacelist;
212 int r_shadow_buffer_numshadowtrispvsbytes;
213 unsigned char *r_shadow_buffer_shadowtrispvs;
214 int r_shadow_buffer_numlighttrispvsbytes;
215 unsigned char *r_shadow_buffer_lighttrispvs;
217 rtexturepool_t *r_shadow_texturepool;
218 rtexture_t *r_shadow_attenuationgradienttexture;
219 rtexture_t *r_shadow_attenuation2dtexture;
220 rtexture_t *r_shadow_attenuation3dtexture;
221 rtexture_t *r_shadow_lightcorona;
222 rtexture_t *r_shadow_shadowmaprectangletexture;
223 rtexture_t *r_shadow_shadowmap2dtexture;
224 rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
225 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
226 int r_shadow_shadowmapsize; // changes for each light based on distance
227 int r_shadow_shadowmaplod; // changes for each light based on distance
229 // lights are reloaded when this changes
230 char r_shadow_mapname[MAX_QPATH];
232 // used only for light filters (cubemaps)
233 rtexturepool_t *r_shadow_filters_texturepool;
235 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"};
236 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"};
237 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
238 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
239 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)"};
240 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"};
241 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
242 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
243 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
244 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
245 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
246 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
247 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
248 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
249 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
250 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)"};
251 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
252 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
253 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
254 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
255 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)"};
256 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"};
257 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
258 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
259 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"};
260 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
261 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
262 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)"};
263 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"};
264 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)"};
265 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
266 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"};
267 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
268 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
269 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
270 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
271 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
272 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
273 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
274 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)"};
275 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)"};
276 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
277 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"};
278 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
279 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
280 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
281 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
282 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
283 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
284 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
285 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
286 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
287 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
289 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
290 #define ATTENTABLESIZE 256
291 // 1D gradient, 2D circle and 3D sphere attenuation textures
292 #define ATTEN1DSIZE 32
293 #define ATTEN2DSIZE 64
294 #define ATTEN3DSIZE 32
296 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
297 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
298 static float r_shadow_attentable[ATTENTABLESIZE+1];
300 rtlight_t *r_shadow_compilingrtlight;
301 static memexpandablearray_t r_shadow_worldlightsarray;
302 dlight_t *r_shadow_selectedlight;
303 dlight_t r_shadow_bufferlight;
304 vec3_t r_editlights_cursorlocation;
306 extern int con_vislines;
308 typedef struct cubemapinfo_s
315 #define MAX_CUBEMAPS 256
316 static int numcubemaps;
317 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
319 void R_Shadow_UncompileWorldLights(void);
320 void R_Shadow_ClearWorldLights(void);
321 void R_Shadow_SaveWorldLights(void);
322 void R_Shadow_LoadWorldLights(void);
323 void R_Shadow_LoadLightsFile(void);
324 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
325 void R_Shadow_EditLights_Reload_f(void);
326 void R_Shadow_ValidateCvars(void);
327 static void R_Shadow_MakeTextures(void);
329 // VorteX: custom editor light sprites
330 #define EDLIGHTSPRSIZE 8
331 cachepic_t *r_editlights_sprcursor;
332 cachepic_t *r_editlights_sprlight;
333 cachepic_t *r_editlights_sprnoshadowlight;
334 cachepic_t *r_editlights_sprcubemaplight;
335 cachepic_t *r_editlights_sprcubemapnoshadowlight;
336 cachepic_t *r_editlights_sprselection;
338 void R_Shadow_FreeShadowMaps(void)
342 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
343 r_shadow_shadowmode = r_shadow_shadowmapping.integer;
344 r_shadow_shadowmaplod = -1;
347 if (r_shadow_fborectangle)
348 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
349 r_shadow_fborectangle = 0;
353 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
357 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
358 if (r_shadow_fbocubeside[i])
359 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
360 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
363 if (r_shadow_shadowmaprectangletexture)
364 R_FreeTexture(r_shadow_shadowmaprectangletexture);
365 r_shadow_shadowmaprectangletexture = NULL;
367 if (r_shadow_shadowmap2dtexture)
368 R_FreeTexture(r_shadow_shadowmap2dtexture);
369 r_shadow_shadowmap2dtexture = NULL;
371 if (r_shadow_shadowmapcubeprojectiontexture)
372 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
373 r_shadow_shadowmapcubeprojectiontexture = NULL;
375 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
376 if (r_shadow_shadowmapcubetexture[i])
377 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
378 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
383 void r_shadow_start(void)
385 // allocate vertex processing arrays
387 r_shadow_attenuationgradienttexture = NULL;
388 r_shadow_attenuation2dtexture = NULL;
389 r_shadow_attenuation3dtexture = NULL;
390 r_shadow_shadowmaprectangletexture = NULL;
391 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
392 r_shadow_shadowmapcubeprojectiontexture = NULL;
393 r_shadow_shadowmap2dtexture = NULL;
394 r_shadow_shadowmapmaxsize = 0;
395 r_shadow_shadowmapsize = 0;
396 r_shadow_shadowmaplod = 0;
397 r_shadow_fborectangle = 0;
398 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
401 R_Shadow_FreeShadowMaps();
403 r_shadow_texturepool = NULL;
404 r_shadow_filters_texturepool = NULL;
405 R_Shadow_ValidateCvars();
406 R_Shadow_MakeTextures();
407 maxshadowtriangles = 0;
408 shadowelements = NULL;
409 maxshadowvertices = 0;
410 shadowvertex3f = NULL;
418 shadowmarklist = NULL;
420 r_shadow_buffer_numleafpvsbytes = 0;
421 r_shadow_buffer_visitingleafpvs = NULL;
422 r_shadow_buffer_leafpvs = NULL;
423 r_shadow_buffer_leaflist = NULL;
424 r_shadow_buffer_numsurfacepvsbytes = 0;
425 r_shadow_buffer_surfacepvs = NULL;
426 r_shadow_buffer_surfacelist = NULL;
427 r_shadow_buffer_numshadowtrispvsbytes = 0;
428 r_shadow_buffer_shadowtrispvs = NULL;
429 r_shadow_buffer_numlighttrispvsbytes = 0;
430 r_shadow_buffer_lighttrispvs = NULL;
433 void r_shadow_shutdown(void)
437 R_Shadow_UncompileWorldLights();
439 R_Shadow_FreeShadowMaps();
443 r_shadow_attenuationgradienttexture = NULL;
444 r_shadow_attenuation2dtexture = NULL;
445 r_shadow_attenuation3dtexture = NULL;
447 if (r_shadow_fborectangle)
448 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
449 r_shadow_fborectangle = 0;
451 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
452 if (r_shadow_fbocubeside[i])
453 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
454 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
457 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
460 R_FreeTexturePool(&r_shadow_texturepool);
461 R_FreeTexturePool(&r_shadow_filters_texturepool);
462 maxshadowtriangles = 0;
464 Mem_Free(shadowelements);
465 shadowelements = NULL;
467 Mem_Free(shadowvertex3f);
468 shadowvertex3f = NULL;
471 Mem_Free(vertexupdate);
474 Mem_Free(vertexremap);
480 Mem_Free(shadowmark);
483 Mem_Free(shadowmarklist);
484 shadowmarklist = NULL;
486 r_shadow_buffer_numleafpvsbytes = 0;
487 if (r_shadow_buffer_visitingleafpvs)
488 Mem_Free(r_shadow_buffer_visitingleafpvs);
489 r_shadow_buffer_visitingleafpvs = NULL;
490 if (r_shadow_buffer_leafpvs)
491 Mem_Free(r_shadow_buffer_leafpvs);
492 r_shadow_buffer_leafpvs = NULL;
493 if (r_shadow_buffer_leaflist)
494 Mem_Free(r_shadow_buffer_leaflist);
495 r_shadow_buffer_leaflist = NULL;
496 r_shadow_buffer_numsurfacepvsbytes = 0;
497 if (r_shadow_buffer_surfacepvs)
498 Mem_Free(r_shadow_buffer_surfacepvs);
499 r_shadow_buffer_surfacepvs = NULL;
500 if (r_shadow_buffer_surfacelist)
501 Mem_Free(r_shadow_buffer_surfacelist);
502 r_shadow_buffer_surfacelist = NULL;
503 r_shadow_buffer_numshadowtrispvsbytes = 0;
504 if (r_shadow_buffer_shadowtrispvs)
505 Mem_Free(r_shadow_buffer_shadowtrispvs);
506 r_shadow_buffer_numlighttrispvsbytes = 0;
507 if (r_shadow_buffer_lighttrispvs)
508 Mem_Free(r_shadow_buffer_lighttrispvs);
511 void r_shadow_newmap(void)
513 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
514 R_Shadow_EditLights_Reload_f();
517 void R_Shadow_Help_f(void)
520 "Documentation on r_shadow system:\n"
522 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
523 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
524 "r_shadow_debuglight : render only this light number (-1 = all)\n"
525 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
526 "r_shadow_gloss2intensity : brightness of forced gloss\n"
527 "r_shadow_glossintensity : brightness of textured gloss\n"
528 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
529 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
530 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
531 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
532 "r_shadow_portallight : use portal visibility for static light precomputation\n"
533 "r_shadow_projectdistance : shadow volume projection distance\n"
534 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
535 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
536 "r_shadow_realtime_world : use high quality world lighting mode\n"
537 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
538 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
539 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
540 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
541 "r_shadow_scissor : use scissor optimization\n"
542 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
543 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
544 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
545 "r_showlighting : useful for performance testing; bright = slow!\n"
546 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
548 "r_shadow_help : this help\n"
552 void R_Shadow_Init(void)
554 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
555 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
556 Cvar_RegisterVariable(&r_shadow_usenormalmap);
557 Cvar_RegisterVariable(&r_shadow_debuglight);
558 Cvar_RegisterVariable(&r_shadow_gloss);
559 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
560 Cvar_RegisterVariable(&r_shadow_glossintensity);
561 Cvar_RegisterVariable(&r_shadow_glossexponent);
562 Cvar_RegisterVariable(&r_shadow_glossexact);
563 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
564 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
565 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
566 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
567 Cvar_RegisterVariable(&r_shadow_portallight);
568 Cvar_RegisterVariable(&r_shadow_projectdistance);
569 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
570 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
571 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
572 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
573 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
574 Cvar_RegisterVariable(&r_shadow_realtime_world);
575 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
576 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
577 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
578 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
579 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
580 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
581 Cvar_RegisterVariable(&r_shadow_scissor);
582 Cvar_RegisterVariable(&r_shadow_shadowmapping);
583 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
584 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
585 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
586 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
587 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
588 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
589 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
590 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
591 Cvar_RegisterVariable(&r_shadow_culltriangles);
592 Cvar_RegisterVariable(&r_shadow_polygonfactor);
593 Cvar_RegisterVariable(&r_shadow_polygonoffset);
594 Cvar_RegisterVariable(&r_shadow_texture3d);
595 Cvar_RegisterVariable(&r_coronas);
596 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
597 Cvar_RegisterVariable(&r_coronas_occlusionquery);
598 Cvar_RegisterVariable(&gl_flashblend);
599 Cvar_RegisterVariable(&gl_ext_separatestencil);
600 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
601 if (gamemode == GAME_TENEBRAE)
603 Cvar_SetValue("r_shadow_gloss", 2);
604 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
606 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
607 R_Shadow_EditLights_Init();
608 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
609 maxshadowtriangles = 0;
610 shadowelements = NULL;
611 maxshadowvertices = 0;
612 shadowvertex3f = NULL;
620 shadowmarklist = NULL;
622 r_shadow_buffer_numleafpvsbytes = 0;
623 r_shadow_buffer_visitingleafpvs = NULL;
624 r_shadow_buffer_leafpvs = NULL;
625 r_shadow_buffer_leaflist = NULL;
626 r_shadow_buffer_numsurfacepvsbytes = 0;
627 r_shadow_buffer_surfacepvs = NULL;
628 r_shadow_buffer_surfacelist = NULL;
629 r_shadow_buffer_shadowtrispvs = NULL;
630 r_shadow_buffer_lighttrispvs = NULL;
631 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
634 matrix4x4_t matrix_attenuationxyz =
637 {0.5, 0.0, 0.0, 0.5},
638 {0.0, 0.5, 0.0, 0.5},
639 {0.0, 0.0, 0.5, 0.5},
644 matrix4x4_t matrix_attenuationz =
647 {0.0, 0.0, 0.5, 0.5},
648 {0.0, 0.0, 0.0, 0.5},
649 {0.0, 0.0, 0.0, 0.5},
654 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
656 // make sure shadowelements is big enough for this volume
657 if (maxshadowtriangles < numtriangles)
659 maxshadowtriangles = numtriangles;
661 Mem_Free(shadowelements);
662 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
664 // make sure shadowvertex3f is big enough for this volume
665 if (maxshadowvertices < numvertices)
667 maxshadowvertices = numvertices;
669 Mem_Free(shadowvertex3f);
670 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
674 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
676 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
677 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
678 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
679 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
680 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
682 if (r_shadow_buffer_visitingleafpvs)
683 Mem_Free(r_shadow_buffer_visitingleafpvs);
684 if (r_shadow_buffer_leafpvs)
685 Mem_Free(r_shadow_buffer_leafpvs);
686 if (r_shadow_buffer_leaflist)
687 Mem_Free(r_shadow_buffer_leaflist);
688 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
689 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
690 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
691 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
693 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
695 if (r_shadow_buffer_surfacepvs)
696 Mem_Free(r_shadow_buffer_surfacepvs);
697 if (r_shadow_buffer_surfacelist)
698 Mem_Free(r_shadow_buffer_surfacelist);
699 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
700 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
701 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
703 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
705 if (r_shadow_buffer_shadowtrispvs)
706 Mem_Free(r_shadow_buffer_shadowtrispvs);
707 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
708 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
710 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
712 if (r_shadow_buffer_lighttrispvs)
713 Mem_Free(r_shadow_buffer_lighttrispvs);
714 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
715 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
719 void R_Shadow_PrepareShadowMark(int numtris)
721 // make sure shadowmark is big enough for this volume
722 if (maxshadowmark < numtris)
724 maxshadowmark = numtris;
726 Mem_Free(shadowmark);
728 Mem_Free(shadowmarklist);
729 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
730 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
734 // if shadowmarkcount wrapped we clear the array and adjust accordingly
735 if (shadowmarkcount == 0)
738 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
743 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)
746 int outtriangles = 0, outvertices = 0;
749 float ratio, direction[3], projectvector[3];
751 if (projectdirection)
752 VectorScale(projectdirection, projectdistance, projectvector);
754 VectorClear(projectvector);
756 // create the vertices
757 if (projectdirection)
759 for (i = 0;i < numshadowmarktris;i++)
761 element = inelement3i + shadowmarktris[i] * 3;
762 for (j = 0;j < 3;j++)
764 if (vertexupdate[element[j]] != vertexupdatenum)
766 vertexupdate[element[j]] = vertexupdatenum;
767 vertexremap[element[j]] = outvertices;
768 vertex = invertex3f + element[j] * 3;
769 // project one copy of the vertex according to projectvector
770 VectorCopy(vertex, outvertex3f);
771 VectorAdd(vertex, projectvector, (outvertex3f + 3));
780 for (i = 0;i < numshadowmarktris;i++)
782 element = inelement3i + shadowmarktris[i] * 3;
783 for (j = 0;j < 3;j++)
785 if (vertexupdate[element[j]] != vertexupdatenum)
787 vertexupdate[element[j]] = vertexupdatenum;
788 vertexremap[element[j]] = outvertices;
789 vertex = invertex3f + element[j] * 3;
790 // project one copy of the vertex to the sphere radius of the light
791 // (FIXME: would projecting it to the light box be better?)
792 VectorSubtract(vertex, projectorigin, direction);
793 ratio = projectdistance / VectorLength(direction);
794 VectorCopy(vertex, outvertex3f);
795 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
803 if (r_shadow_frontsidecasting.integer)
805 for (i = 0;i < numshadowmarktris;i++)
807 int remappedelement[3];
809 const int *neighbortriangle;
811 markindex = shadowmarktris[i] * 3;
812 element = inelement3i + markindex;
813 neighbortriangle = inneighbor3i + markindex;
814 // output the front and back triangles
815 outelement3i[0] = vertexremap[element[0]];
816 outelement3i[1] = vertexremap[element[1]];
817 outelement3i[2] = vertexremap[element[2]];
818 outelement3i[3] = vertexremap[element[2]] + 1;
819 outelement3i[4] = vertexremap[element[1]] + 1;
820 outelement3i[5] = vertexremap[element[0]] + 1;
824 // output the sides (facing outward from this triangle)
825 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
827 remappedelement[0] = vertexremap[element[0]];
828 remappedelement[1] = vertexremap[element[1]];
829 outelement3i[0] = remappedelement[1];
830 outelement3i[1] = remappedelement[0];
831 outelement3i[2] = remappedelement[0] + 1;
832 outelement3i[3] = remappedelement[1];
833 outelement3i[4] = remappedelement[0] + 1;
834 outelement3i[5] = remappedelement[1] + 1;
839 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
841 remappedelement[1] = vertexremap[element[1]];
842 remappedelement[2] = vertexremap[element[2]];
843 outelement3i[0] = remappedelement[2];
844 outelement3i[1] = remappedelement[1];
845 outelement3i[2] = remappedelement[1] + 1;
846 outelement3i[3] = remappedelement[2];
847 outelement3i[4] = remappedelement[1] + 1;
848 outelement3i[5] = remappedelement[2] + 1;
853 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
855 remappedelement[0] = vertexremap[element[0]];
856 remappedelement[2] = vertexremap[element[2]];
857 outelement3i[0] = remappedelement[0];
858 outelement3i[1] = remappedelement[2];
859 outelement3i[2] = remappedelement[2] + 1;
860 outelement3i[3] = remappedelement[0];
861 outelement3i[4] = remappedelement[2] + 1;
862 outelement3i[5] = remappedelement[0] + 1;
871 for (i = 0;i < numshadowmarktris;i++)
873 int remappedelement[3];
875 const int *neighbortriangle;
877 markindex = shadowmarktris[i] * 3;
878 element = inelement3i + markindex;
879 neighbortriangle = inneighbor3i + markindex;
880 // output the front and back triangles
881 outelement3i[0] = vertexremap[element[2]];
882 outelement3i[1] = vertexremap[element[1]];
883 outelement3i[2] = vertexremap[element[0]];
884 outelement3i[3] = vertexremap[element[0]] + 1;
885 outelement3i[4] = vertexremap[element[1]] + 1;
886 outelement3i[5] = vertexremap[element[2]] + 1;
890 // output the sides (facing outward from this triangle)
891 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
893 remappedelement[0] = vertexremap[element[0]];
894 remappedelement[1] = vertexremap[element[1]];
895 outelement3i[0] = remappedelement[0];
896 outelement3i[1] = remappedelement[1];
897 outelement3i[2] = remappedelement[1] + 1;
898 outelement3i[3] = remappedelement[0];
899 outelement3i[4] = remappedelement[1] + 1;
900 outelement3i[5] = remappedelement[0] + 1;
905 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
907 remappedelement[1] = vertexremap[element[1]];
908 remappedelement[2] = vertexremap[element[2]];
909 outelement3i[0] = remappedelement[1];
910 outelement3i[1] = remappedelement[2];
911 outelement3i[2] = remappedelement[2] + 1;
912 outelement3i[3] = remappedelement[1];
913 outelement3i[4] = remappedelement[2] + 1;
914 outelement3i[5] = remappedelement[1] + 1;
919 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
921 remappedelement[0] = vertexremap[element[0]];
922 remappedelement[2] = vertexremap[element[2]];
923 outelement3i[0] = remappedelement[2];
924 outelement3i[1] = remappedelement[0];
925 outelement3i[2] = remappedelement[0] + 1;
926 outelement3i[3] = remappedelement[2];
927 outelement3i[4] = remappedelement[0] + 1;
928 outelement3i[5] = remappedelement[2] + 1;
936 *outnumvertices = outvertices;
940 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)
943 int outtriangles = 0, outvertices = 0;
946 float ratio, direction[3], projectvector[3];
949 if (projectdirection)
950 VectorScale(projectdirection, projectdistance, projectvector);
952 VectorClear(projectvector);
954 for (i = 0;i < numshadowmarktris;i++)
956 int remappedelement[3];
958 const int *neighbortriangle;
960 markindex = shadowmarktris[i] * 3;
961 neighbortriangle = inneighbor3i + markindex;
962 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
963 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
964 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
965 if (side[0] + side[1] + side[2] == 0)
969 element = inelement3i + markindex;
971 // create the vertices
972 for (j = 0;j < 3;j++)
974 if (side[j] + side[j+1] == 0)
977 if (vertexupdate[k] != vertexupdatenum)
979 vertexupdate[k] = vertexupdatenum;
980 vertexremap[k] = outvertices;
981 vertex = invertex3f + k * 3;
982 VectorCopy(vertex, outvertex3f);
983 if (projectdirection)
985 // project one copy of the vertex according to projectvector
986 VectorAdd(vertex, projectvector, (outvertex3f + 3));
990 // project one copy of the vertex to the sphere radius of the light
991 // (FIXME: would projecting it to the light box be better?)
992 VectorSubtract(vertex, projectorigin, direction);
993 ratio = projectdistance / VectorLength(direction);
994 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1001 // output the sides (facing outward from this triangle)
1004 remappedelement[0] = vertexremap[element[0]];
1005 remappedelement[1] = vertexremap[element[1]];
1006 outelement3i[0] = remappedelement[1];
1007 outelement3i[1] = remappedelement[0];
1008 outelement3i[2] = remappedelement[0] + 1;
1009 outelement3i[3] = remappedelement[1];
1010 outelement3i[4] = remappedelement[0] + 1;
1011 outelement3i[5] = remappedelement[1] + 1;
1018 remappedelement[1] = vertexremap[element[1]];
1019 remappedelement[2] = vertexremap[element[2]];
1020 outelement3i[0] = remappedelement[2];
1021 outelement3i[1] = remappedelement[1];
1022 outelement3i[2] = remappedelement[1] + 1;
1023 outelement3i[3] = remappedelement[2];
1024 outelement3i[4] = remappedelement[1] + 1;
1025 outelement3i[5] = remappedelement[2] + 1;
1032 remappedelement[0] = vertexremap[element[0]];
1033 remappedelement[2] = vertexremap[element[2]];
1034 outelement3i[0] = remappedelement[0];
1035 outelement3i[1] = remappedelement[2];
1036 outelement3i[2] = remappedelement[2] + 1;
1037 outelement3i[3] = remappedelement[0];
1038 outelement3i[4] = remappedelement[2] + 1;
1039 outelement3i[5] = remappedelement[0] + 1;
1046 *outnumvertices = outvertices;
1047 return outtriangles;
1050 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)
1056 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1058 tend = firsttriangle + numtris;
1059 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1061 // surface box entirely inside light box, no box cull
1062 if (projectdirection)
1064 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1066 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1067 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1068 shadowmarklist[numshadowmark++] = t;
1073 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1074 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1075 shadowmarklist[numshadowmark++] = t;
1080 // surface box not entirely inside light box, cull each triangle
1081 if (projectdirection)
1083 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1085 v[0] = invertex3f + e[0] * 3;
1086 v[1] = invertex3f + e[1] * 3;
1087 v[2] = invertex3f + e[2] * 3;
1088 TriangleNormal(v[0], v[1], v[2], normal);
1089 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1090 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1091 shadowmarklist[numshadowmark++] = t;
1096 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1098 v[0] = invertex3f + e[0] * 3;
1099 v[1] = invertex3f + e[1] * 3;
1100 v[2] = invertex3f + e[2] * 3;
1101 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1102 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1103 shadowmarklist[numshadowmark++] = t;
1109 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1114 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1116 // check if the shadow volume intersects the near plane
1118 // a ray between the eye and light origin may intersect the caster,
1119 // indicating that the shadow may touch the eye location, however we must
1120 // test the near plane (a polygon), not merely the eye location, so it is
1121 // easiest to enlarge the caster bounding shape slightly for this.
1127 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)
1129 int i, tris, outverts;
1130 if (projectdistance < 0.1)
1132 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1135 if (!numverts || !nummarktris)
1137 // make sure shadowelements is big enough for this volume
1138 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1139 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1141 if (maxvertexupdate < numverts)
1143 maxvertexupdate = numverts;
1145 Mem_Free(vertexupdate);
1147 Mem_Free(vertexremap);
1148 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1149 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1150 vertexupdatenum = 0;
1153 if (vertexupdatenum == 0)
1155 vertexupdatenum = 1;
1156 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1157 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1160 for (i = 0;i < nummarktris;i++)
1161 shadowmark[marktris[i]] = shadowmarkcount;
1163 if (r_shadow_compilingrtlight)
1165 // if we're compiling an rtlight, capture the mesh
1166 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1167 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1168 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1169 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1173 // decide which type of shadow to generate and set stencil mode
1174 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1175 // generate the sides or a solid volume, depending on type
1176 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1177 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1179 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1180 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1181 r_refdef.stats.lights_shadowtriangles += tris;
1183 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1184 GL_LockArrays(0, outverts);
1185 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1187 // increment stencil if frontface is infront of depthbuffer
1188 GL_CullFace(r_refdef.view.cullface_front);
1189 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1190 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1191 // decrement stencil if backface is infront of depthbuffer
1192 GL_CullFace(r_refdef.view.cullface_back);
1193 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1195 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1197 // decrement stencil if backface is behind depthbuffer
1198 GL_CullFace(r_refdef.view.cullface_front);
1199 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1200 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1201 // increment stencil if frontface is behind depthbuffer
1202 GL_CullFace(r_refdef.view.cullface_back);
1203 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1205 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1206 GL_LockArrays(0, 0);
1211 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)
1213 int i, tris = nummarktris;
1216 if (!numverts || !nummarktris)
1218 // make sure shadowelements is big enough for this mesh
1219 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1220 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1222 // gather up the (sparse) triangles into one array
1223 outelement3i = shadowelements;
1224 for (i = 0;i < nummarktris;i++)
1226 element = elements + marktris[i] * 3;
1227 outelement3i[0] = element[0];
1228 outelement3i[1] = element[1];
1229 outelement3i[2] = element[2];
1233 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1234 r_refdef.stats.lights_shadowtriangles += tris;
1235 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1236 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1239 static void R_Shadow_MakeTextures_MakeCorona(void)
1243 unsigned char pixels[32][32][4];
1244 for (y = 0;y < 32;y++)
1246 dy = (y - 15.5f) * (1.0f / 16.0f);
1247 for (x = 0;x < 32;x++)
1249 dx = (x - 15.5f) * (1.0f / 16.0f);
1250 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1251 a = bound(0, a, 255);
1252 pixels[y][x][0] = a;
1253 pixels[y][x][1] = a;
1254 pixels[y][x][2] = a;
1255 pixels[y][x][3] = 255;
1258 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1261 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1263 float dist = sqrt(x*x+y*y+z*z);
1264 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1265 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1266 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1269 static void R_Shadow_MakeTextures(void)
1272 float intensity, dist;
1274 R_FreeTexturePool(&r_shadow_texturepool);
1275 r_shadow_texturepool = R_AllocTexturePool();
1276 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1277 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1278 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1279 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1280 for (x = 0;x <= ATTENTABLESIZE;x++)
1282 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1283 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1284 r_shadow_attentable[x] = bound(0, intensity, 1);
1286 // 1D gradient texture
1287 for (x = 0;x < ATTEN1DSIZE;x++)
1288 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1289 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);
1290 // 2D circle texture
1291 for (y = 0;y < ATTEN2DSIZE;y++)
1292 for (x = 0;x < ATTEN2DSIZE;x++)
1293 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);
1294 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);
1295 // 3D sphere texture
1296 if (r_shadow_texture3d.integer && gl_texture3d)
1298 for (z = 0;z < ATTEN3DSIZE;z++)
1299 for (y = 0;y < ATTEN3DSIZE;y++)
1300 for (x = 0;x < ATTEN3DSIZE;x++)
1301 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));
1302 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);
1305 r_shadow_attenuation3dtexture = NULL;
1308 R_Shadow_MakeTextures_MakeCorona();
1310 // Editor light sprites
1311 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1312 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1313 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1314 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1315 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1316 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1319 void R_Shadow_ValidateCvars(void)
1321 if (r_shadow_texture3d.integer && !gl_texture3d)
1322 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1323 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1324 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1325 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1326 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1329 void R_Shadow_RenderMode_Begin(void)
1333 R_Shadow_ValidateCvars();
1335 if (!r_shadow_attenuation2dtexture
1336 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1337 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1338 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1339 R_Shadow_MakeTextures();
1342 R_Mesh_ColorPointer(NULL, 0, 0);
1343 R_Mesh_ResetTextureState();
1344 GL_BlendFunc(GL_ONE, GL_ZERO);
1345 GL_DepthRange(0, 1);
1346 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1348 GL_DepthMask(false);
1349 GL_Color(0, 0, 0, 1);
1350 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
1352 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1354 if (gl_ext_separatestencil.integer)
1356 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1357 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1359 else if (gl_ext_stenciltwoside.integer)
1361 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1362 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1366 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1367 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1370 if (r_glsl.integer && gl_support_fragment_shader)
1371 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1372 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1373 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1375 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1378 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1379 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1380 r_shadow_drawbuffer = drawbuffer;
1381 r_shadow_readbuffer = readbuffer;
1384 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1386 rsurface.rtlight = rtlight;
1389 void R_Shadow_RenderMode_Reset(void)
1392 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1394 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1396 if (gl_support_ext_framebuffer_object)
1398 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1400 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1401 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1402 R_SetViewport(&r_refdef.view.viewport);
1403 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1404 R_Mesh_ColorPointer(NULL, 0, 0);
1405 R_Mesh_ResetTextureState();
1406 GL_DepthRange(0, 1);
1408 GL_DepthMask(false);
1409 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1410 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1411 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1412 qglStencilMask(~0);CHECKGLERROR
1413 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1414 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1415 GL_CullFace(r_refdef.view.cullface_back);
1416 GL_Color(1, 1, 1, 1);
1417 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1418 GL_BlendFunc(GL_ONE, GL_ZERO);
1419 R_SetupGenericShader(false);
1420 r_shadow_usingshadowmaprect = false;
1421 r_shadow_usingshadowmapcube = false;
1422 r_shadow_usingshadowmap2d = false;
1426 void R_Shadow_ClearStencil(void)
1429 GL_Clear(GL_STENCIL_BUFFER_BIT);
1430 r_refdef.stats.lights_clears++;
1433 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1435 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1436 if (r_shadow_rendermode == mode)
1439 R_Shadow_RenderMode_Reset();
1440 GL_ColorMask(0, 0, 0, 0);
1441 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1442 R_SetupDepthOrShadowShader();
1443 qglDepthFunc(GL_LESS);CHECKGLERROR
1444 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1445 r_shadow_rendermode = mode;
1450 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1451 GL_CullFace(GL_NONE);
1452 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1453 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1455 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1456 GL_CullFace(GL_NONE);
1457 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1458 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1460 case R_SHADOW_RENDERMODE_ZPASS_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_KEEP, GL_INCR);CHECKGLERROR
1466 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1467 qglStencilMask(~0);CHECKGLERROR
1468 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1470 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1471 GL_CullFace(GL_NONE);
1472 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1473 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1474 qglStencilMask(~0);CHECKGLERROR
1475 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1476 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1477 qglStencilMask(~0);CHECKGLERROR
1478 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1483 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1488 float nearclip, farclip;
1489 r_viewport_t viewport;
1491 maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
1492 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1494 r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1495 r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1496 r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1497 r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
1498 r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
1499 if (r_shadow_shadowmapping.integer == 1)
1501 // complex unrolled cube approach (more flexible)
1502 //if (!r_shadow_shadowmapcubeprojectiontexture)
1503 // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1504 if (!r_shadow_shadowmap2dtexture)
1507 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4);
1508 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1509 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1510 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1514 R_Shadow_RenderMode_Reset();
1515 if (r_shadow_shadowmap2dtexture)
1517 // render depth into the fbo, do not render color at all
1518 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1519 qglDrawBuffer(GL_NONE);CHECKGLERROR
1520 qglReadBuffer(GL_NONE);CHECKGLERROR
1521 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1522 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1524 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1525 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1527 R_SetupDepthOrShadowShader();
1531 R_SetupShowDepthShader();
1532 qglClearColor(1,1,1,1);CHECKGLERROR
1534 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1535 r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
1536 r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
1537 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1539 else if (r_shadow_shadowmapping.integer == 2)
1541 // complex unrolled cube approach (more flexible)
1542 //if (!r_shadow_shadowmapcubeprojectiontexture)
1543 // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1544 if (!r_shadow_shadowmaprectangletexture)
1547 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4);
1548 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1549 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1550 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1554 R_Shadow_RenderMode_Reset();
1555 if (r_shadow_shadowmaprectangletexture)
1557 // render depth into the fbo, do not render color at all
1558 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1559 qglDrawBuffer(GL_NONE);CHECKGLERROR
1560 qglReadBuffer(GL_NONE);CHECKGLERROR
1561 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1562 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1564 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1565 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1567 R_SetupDepthOrShadowShader();
1571 R_SetupShowDepthShader();
1572 qglClearColor(1,1,1,1);CHECKGLERROR
1574 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1575 r_shadow_shadowmap_texturescale[0] = size;
1576 r_shadow_shadowmap_texturescale[1] = size;
1577 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1579 else if (r_shadow_shadowmapping.integer == 3)
1581 // simple cube approach
1582 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1585 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size);
1586 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1587 for (i = 0;i < 6;i++)
1589 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1590 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
1595 R_Shadow_RenderMode_Reset();
1596 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1598 // render depth into the fbo, do not render color at all
1599 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1600 qglDrawBuffer(GL_NONE);CHECKGLERROR
1601 qglReadBuffer(GL_NONE);CHECKGLERROR
1602 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1603 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1605 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1606 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1608 R_SetupDepthOrShadowShader();
1612 R_SetupShowDepthShader();
1613 qglClearColor(1,1,1,1);CHECKGLERROR
1615 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1616 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1617 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1618 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1621 R_SetViewport(&viewport);
1622 GL_PolygonOffset(0, 0);
1623 GL_CullFace(GL_NONE); // quake is backwards
1624 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1627 qglClearDepth(1);CHECKGLERROR
1630 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1634 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1637 R_Shadow_RenderMode_Reset();
1638 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1641 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1645 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1646 // only draw light where this geometry was already rendered AND the
1647 // stencil is 128 (values other than this mean shadow)
1648 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1650 r_shadow_rendermode = r_shadow_lightingrendermode;
1651 // do global setup needed for the chosen lighting mode
1652 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1654 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1655 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1659 if (r_shadow_shadowmapping.integer == 1)
1661 r_shadow_usingshadowmap2d = true;
1662 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1665 else if (r_shadow_shadowmapping.integer == 2)
1667 r_shadow_usingshadowmaprect = true;
1668 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1671 else if (r_shadow_shadowmapping.integer == 3)
1673 r_shadow_usingshadowmapcube = true;
1674 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1679 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1680 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1681 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1685 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1688 R_Shadow_RenderMode_Reset();
1689 GL_BlendFunc(GL_ONE, GL_ONE);
1690 GL_DepthRange(0, 1);
1691 GL_DepthTest(r_showshadowvolumes.integer < 2);
1692 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1693 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1694 GL_CullFace(GL_NONE);
1695 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1698 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1701 R_Shadow_RenderMode_Reset();
1702 GL_BlendFunc(GL_ONE, GL_ONE);
1703 GL_DepthRange(0, 1);
1704 GL_DepthTest(r_showlighting.integer < 2);
1705 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1708 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1712 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1713 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1715 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1718 void R_Shadow_RenderMode_End(void)
1721 R_Shadow_RenderMode_Reset();
1722 R_Shadow_RenderMode_ActiveLight(NULL);
1724 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
1725 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1728 int bboxedges[12][2] =
1747 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1749 int i, ix1, iy1, ix2, iy2;
1750 float x1, y1, x2, y2;
1752 float vertex[20][3];
1761 r_shadow_lightscissor[0] = r_refdef.view.x;
1762 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
1763 r_shadow_lightscissor[2] = r_refdef.view.width;
1764 r_shadow_lightscissor[3] = r_refdef.view.height;
1766 if (!r_shadow_scissor.integer)
1769 // if view is inside the light box, just say yes it's visible
1770 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1773 x1 = y1 = x2 = y2 = 0;
1775 // transform all corners that are infront of the nearclip plane
1776 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1777 plane4f[3] = r_refdef.view.frustum[4].dist;
1779 for (i = 0;i < 8;i++)
1781 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1782 dist[i] = DotProduct4(corner[i], plane4f);
1783 sign[i] = dist[i] > 0;
1786 VectorCopy(corner[i], vertex[numvertices]);
1790 // if some points are behind the nearclip, add clipped edge points to make
1791 // sure that the scissor boundary is complete
1792 if (numvertices > 0 && numvertices < 8)
1794 // add clipped edge points
1795 for (i = 0;i < 12;i++)
1797 j = bboxedges[i][0];
1798 k = bboxedges[i][1];
1799 if (sign[j] != sign[k])
1801 f = dist[j] / (dist[j] - dist[k]);
1802 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1808 // if we have no points to check, the light is behind the view plane
1812 // if we have some points to transform, check what screen area is covered
1813 x1 = y1 = x2 = y2 = 0;
1815 //Con_Printf("%i vertices to transform...\n", numvertices);
1816 for (i = 0;i < numvertices;i++)
1818 VectorCopy(vertex[i], v);
1819 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1820 //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]);
1823 if (x1 > v2[0]) x1 = v2[0];
1824 if (x2 < v2[0]) x2 = v2[0];
1825 if (y1 > v2[1]) y1 = v2[1];
1826 if (y2 < v2[1]) y2 = v2[1];
1835 // now convert the scissor rectangle to integer screen coordinates
1836 ix1 = (int)(x1 - 1.0f);
1837 iy1 = (int)(y1 - 1.0f);
1838 ix2 = (int)(x2 + 1.0f);
1839 iy2 = (int)(y2 + 1.0f);
1840 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1842 // clamp it to the screen
1843 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1844 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1845 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1846 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1848 // if it is inside out, it's not visible
1849 if (ix2 <= ix1 || iy2 <= iy1)
1852 // the light area is visible, set up the scissor rectangle
1853 r_shadow_lightscissor[0] = ix1;
1854 r_shadow_lightscissor[1] = vid.height - iy2;
1855 r_shadow_lightscissor[2] = ix2 - ix1;
1856 r_shadow_lightscissor[3] = iy2 - iy1;
1858 r_refdef.stats.lights_scissored++;
1862 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1864 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1865 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1866 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1867 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1868 if (r_textureunits.integer >= 3)
1870 if (VectorLength2(diffusecolor) > 0)
1872 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1874 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1875 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1876 if ((dot = DotProduct(n, v)) < 0)
1878 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1879 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1882 VectorCopy(ambientcolor, color4f);
1883 if (r_refdef.fogenabled)
1886 f = FogPoint_Model(vertex3f);
1887 VectorScale(color4f, f, color4f);
1894 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1896 VectorCopy(ambientcolor, color4f);
1897 if (r_refdef.fogenabled)
1900 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1901 f = FogPoint_Model(vertex3f);
1902 VectorScale(color4f, f, color4f);
1908 else if (r_textureunits.integer >= 2)
1910 if (VectorLength2(diffusecolor) > 0)
1912 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1914 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1915 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1917 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1918 if ((dot = DotProduct(n, v)) < 0)
1920 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1921 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1922 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1923 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1927 color4f[0] = ambientcolor[0] * distintensity;
1928 color4f[1] = ambientcolor[1] * distintensity;
1929 color4f[2] = ambientcolor[2] * distintensity;
1931 if (r_refdef.fogenabled)
1934 f = FogPoint_Model(vertex3f);
1935 VectorScale(color4f, f, color4f);
1939 VectorClear(color4f);
1945 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1947 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1948 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1950 color4f[0] = ambientcolor[0] * distintensity;
1951 color4f[1] = ambientcolor[1] * distintensity;
1952 color4f[2] = ambientcolor[2] * distintensity;
1953 if (r_refdef.fogenabled)
1956 f = FogPoint_Model(vertex3f);
1957 VectorScale(color4f, f, color4f);
1961 VectorClear(color4f);
1968 if (VectorLength2(diffusecolor) > 0)
1970 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1972 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1973 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1975 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1976 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1977 if ((dot = DotProduct(n, v)) < 0)
1979 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1980 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1981 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1982 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1986 color4f[0] = ambientcolor[0] * distintensity;
1987 color4f[1] = ambientcolor[1] * distintensity;
1988 color4f[2] = ambientcolor[2] * distintensity;
1990 if (r_refdef.fogenabled)
1993 f = FogPoint_Model(vertex3f);
1994 VectorScale(color4f, f, color4f);
1998 VectorClear(color4f);
2004 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2006 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2007 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2009 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2010 color4f[0] = ambientcolor[0] * distintensity;
2011 color4f[1] = ambientcolor[1] * distintensity;
2012 color4f[2] = ambientcolor[2] * distintensity;
2013 if (r_refdef.fogenabled)
2016 f = FogPoint_Model(vertex3f);
2017 VectorScale(color4f, f, color4f);
2021 VectorClear(color4f);
2028 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2030 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2033 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2034 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2035 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2036 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2037 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2039 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2041 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2042 // the cubemap normalizes this for us
2043 out3f[0] = DotProduct(svector3f, lightdir);
2044 out3f[1] = DotProduct(tvector3f, lightdir);
2045 out3f[2] = DotProduct(normal3f, lightdir);
2049 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2052 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2053 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2054 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2055 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2056 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2057 float lightdir[3], eyedir[3], halfdir[3];
2058 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2060 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2061 VectorNormalize(lightdir);
2062 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2063 VectorNormalize(eyedir);
2064 VectorAdd(lightdir, eyedir, halfdir);
2065 // the cubemap normalizes this for us
2066 out3f[0] = DotProduct(svector3f, halfdir);
2067 out3f[1] = DotProduct(tvector3f, halfdir);
2068 out3f[2] = DotProduct(normal3f, halfdir);
2072 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)
2074 // used to display how many times a surface is lit for level design purposes
2075 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2078 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)
2080 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2081 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2082 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2083 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2085 R_Mesh_ColorPointer(NULL, 0, 0);
2086 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2087 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2088 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2089 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2090 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2091 if (rsurface.texture->backgroundcurrentskinframe)
2093 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2094 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2095 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2096 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2098 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2099 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2100 if(rsurface.texture->colormapping)
2102 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2103 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2105 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2106 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2107 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2108 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2109 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2110 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2112 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2114 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2115 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2117 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2121 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)
2123 // shared final code for all the dot3 layers
2125 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2126 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2128 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2129 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2133 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)
2136 // colorscale accounts for how much we multiply the brightness
2139 // mult is how many times the final pass of the lighting will be
2140 // performed to get more brightness than otherwise possible.
2142 // Limit mult to 64 for sanity sake.
2144 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2146 // 3 3D combine path (Geforce3, Radeon 8500)
2147 memset(&m, 0, sizeof(m));
2148 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2149 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2150 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2151 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2152 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2153 m.tex[1] = R_GetTexture(basetexture);
2154 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2155 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2156 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2157 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2158 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2159 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2160 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2161 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2162 m.texmatrix[2] = rsurface.entitytolight;
2163 GL_BlendFunc(GL_ONE, GL_ONE);
2165 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2167 // 2 3D combine path (Geforce3, original Radeon)
2168 memset(&m, 0, sizeof(m));
2169 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2170 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2171 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2172 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2173 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2174 m.tex[1] = R_GetTexture(basetexture);
2175 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2176 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2177 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2178 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2179 GL_BlendFunc(GL_ONE, GL_ONE);
2181 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2183 // 4 2D combine path (Geforce3, Radeon 8500)
2184 memset(&m, 0, sizeof(m));
2185 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2186 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2187 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2188 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2189 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2190 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2191 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2192 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2193 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2194 m.texmatrix[1] = rsurface.entitytoattenuationz;
2195 m.tex[2] = R_GetTexture(basetexture);
2196 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2197 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2198 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2199 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2200 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2202 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2203 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2204 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2205 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2206 m.texmatrix[3] = rsurface.entitytolight;
2208 GL_BlendFunc(GL_ONE, GL_ONE);
2210 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2212 // 3 2D combine path (Geforce3, original Radeon)
2213 memset(&m, 0, sizeof(m));
2214 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2215 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2216 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2217 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2218 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2219 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2220 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2221 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2222 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2223 m.texmatrix[1] = rsurface.entitytoattenuationz;
2224 m.tex[2] = R_GetTexture(basetexture);
2225 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2226 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2227 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2228 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2229 GL_BlendFunc(GL_ONE, GL_ONE);
2233 // 2/2/2 2D combine path (any dot3 card)
2234 memset(&m, 0, sizeof(m));
2235 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2236 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2237 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2238 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2239 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2240 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2241 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2242 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2243 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2244 m.texmatrix[1] = rsurface.entitytoattenuationz;
2245 R_Mesh_TextureState(&m);
2246 GL_ColorMask(0,0,0,1);
2247 GL_BlendFunc(GL_ONE, GL_ZERO);
2248 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2251 memset(&m, 0, sizeof(m));
2252 m.tex[0] = R_GetTexture(basetexture);
2253 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2254 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2255 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2256 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2257 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2259 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2260 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2261 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2262 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2263 m.texmatrix[1] = rsurface.entitytolight;
2265 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2267 // this final code is shared
2268 R_Mesh_TextureState(&m);
2269 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);
2272 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)
2275 // colorscale accounts for how much we multiply the brightness
2278 // mult is how many times the final pass of the lighting will be
2279 // performed to get more brightness than otherwise possible.
2281 // Limit mult to 64 for sanity sake.
2283 // generate normalization cubemap texcoords
2284 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2285 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2287 // 3/2 3D combine path (Geforce3, Radeon 8500)
2288 memset(&m, 0, sizeof(m));
2289 m.tex[0] = R_GetTexture(normalmaptexture);
2290 m.texcombinergb[0] = GL_REPLACE;
2291 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2292 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2293 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2294 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2295 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2296 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2297 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2298 m.pointer_texcoord_bufferobject[1] = 0;
2299 m.pointer_texcoord_bufferoffset[1] = 0;
2300 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2301 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2302 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2303 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2304 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2305 R_Mesh_TextureState(&m);
2306 GL_ColorMask(0,0,0,1);
2307 GL_BlendFunc(GL_ONE, GL_ZERO);
2308 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2311 memset(&m, 0, sizeof(m));
2312 m.tex[0] = R_GetTexture(basetexture);
2313 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2314 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2315 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2316 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2317 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2319 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2320 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2321 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2322 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2323 m.texmatrix[1] = rsurface.entitytolight;
2325 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2327 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2329 // 1/2/2 3D combine path (original Radeon)
2330 memset(&m, 0, sizeof(m));
2331 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2332 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2333 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2334 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2335 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2336 R_Mesh_TextureState(&m);
2337 GL_ColorMask(0,0,0,1);
2338 GL_BlendFunc(GL_ONE, GL_ZERO);
2339 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2342 memset(&m, 0, sizeof(m));
2343 m.tex[0] = R_GetTexture(normalmaptexture);
2344 m.texcombinergb[0] = GL_REPLACE;
2345 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2346 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2347 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2348 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2349 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2350 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2351 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2352 m.pointer_texcoord_bufferobject[1] = 0;
2353 m.pointer_texcoord_bufferoffset[1] = 0;
2354 R_Mesh_TextureState(&m);
2355 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2356 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2359 memset(&m, 0, sizeof(m));
2360 m.tex[0] = R_GetTexture(basetexture);
2361 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2362 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2363 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2364 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2365 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2367 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2368 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2369 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2370 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2371 m.texmatrix[1] = rsurface.entitytolight;
2373 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2375 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2377 // 2/2 3D combine path (original Radeon)
2378 memset(&m, 0, sizeof(m));
2379 m.tex[0] = R_GetTexture(normalmaptexture);
2380 m.texcombinergb[0] = GL_REPLACE;
2381 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2382 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2383 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2384 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2385 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2386 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2387 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2388 m.pointer_texcoord_bufferobject[1] = 0;
2389 m.pointer_texcoord_bufferoffset[1] = 0;
2390 R_Mesh_TextureState(&m);
2391 GL_ColorMask(0,0,0,1);
2392 GL_BlendFunc(GL_ONE, GL_ZERO);
2393 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2396 memset(&m, 0, sizeof(m));
2397 m.tex[0] = R_GetTexture(basetexture);
2398 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2399 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2400 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2401 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2402 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2403 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2404 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2405 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2406 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2407 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2409 else if (r_textureunits.integer >= 4)
2411 // 4/2 2D combine path (Geforce3, Radeon 8500)
2412 memset(&m, 0, sizeof(m));
2413 m.tex[0] = R_GetTexture(normalmaptexture);
2414 m.texcombinergb[0] = GL_REPLACE;
2415 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2416 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2417 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2418 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2419 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2420 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2421 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2422 m.pointer_texcoord_bufferobject[1] = 0;
2423 m.pointer_texcoord_bufferoffset[1] = 0;
2424 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2425 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2426 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2427 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2428 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2429 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2430 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2431 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2432 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2433 m.texmatrix[3] = rsurface.entitytoattenuationz;
2434 R_Mesh_TextureState(&m);
2435 GL_ColorMask(0,0,0,1);
2436 GL_BlendFunc(GL_ONE, GL_ZERO);
2437 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2440 memset(&m, 0, sizeof(m));
2441 m.tex[0] = R_GetTexture(basetexture);
2442 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2443 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2444 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2445 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2446 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2448 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2449 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2450 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2451 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2452 m.texmatrix[1] = rsurface.entitytolight;
2454 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2458 // 2/2/2 2D combine path (any dot3 card)
2459 memset(&m, 0, sizeof(m));
2460 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2461 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2462 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2463 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2464 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2465 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2466 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2467 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2468 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2469 m.texmatrix[1] = rsurface.entitytoattenuationz;
2470 R_Mesh_TextureState(&m);
2471 GL_ColorMask(0,0,0,1);
2472 GL_BlendFunc(GL_ONE, GL_ZERO);
2473 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2476 memset(&m, 0, sizeof(m));
2477 m.tex[0] = R_GetTexture(normalmaptexture);
2478 m.texcombinergb[0] = GL_REPLACE;
2479 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2480 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2481 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2482 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2483 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2484 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2485 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2486 m.pointer_texcoord_bufferobject[1] = 0;
2487 m.pointer_texcoord_bufferoffset[1] = 0;
2488 R_Mesh_TextureState(&m);
2489 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2490 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2493 memset(&m, 0, sizeof(m));
2494 m.tex[0] = R_GetTexture(basetexture);
2495 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2496 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2497 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2498 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2499 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2501 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2502 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2503 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2504 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2505 m.texmatrix[1] = rsurface.entitytolight;
2507 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2509 // this final code is shared
2510 R_Mesh_TextureState(&m);
2511 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);
2514 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)
2516 float glossexponent;
2518 // FIXME: detect blendsquare!
2519 //if (!gl_support_blendsquare)
2522 // generate normalization cubemap texcoords
2523 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2524 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2526 // 2/0/0/1/2 3D combine blendsquare path
2527 memset(&m, 0, sizeof(m));
2528 m.tex[0] = R_GetTexture(normalmaptexture);
2529 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2530 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2531 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2532 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2533 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2534 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2535 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2536 m.pointer_texcoord_bufferobject[1] = 0;
2537 m.pointer_texcoord_bufferoffset[1] = 0;
2538 R_Mesh_TextureState(&m);
2539 GL_ColorMask(0,0,0,1);
2540 // this squares the result
2541 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2542 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2544 // second and third pass
2545 R_Mesh_ResetTextureState();
2546 // square alpha in framebuffer a few times to make it shiny
2547 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2548 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2549 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2552 memset(&m, 0, sizeof(m));
2553 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2554 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2555 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2556 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2557 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2558 R_Mesh_TextureState(&m);
2559 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2560 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2563 memset(&m, 0, sizeof(m));
2564 m.tex[0] = R_GetTexture(glosstexture);
2565 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2566 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2567 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2568 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2569 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2571 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2572 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2573 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2574 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2575 m.texmatrix[1] = rsurface.entitytolight;
2577 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2579 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2581 // 2/0/0/2 3D combine blendsquare path
2582 memset(&m, 0, sizeof(m));
2583 m.tex[0] = R_GetTexture(normalmaptexture);
2584 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2585 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2586 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2587 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2588 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2589 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2590 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2591 m.pointer_texcoord_bufferobject[1] = 0;
2592 m.pointer_texcoord_bufferoffset[1] = 0;
2593 R_Mesh_TextureState(&m);
2594 GL_ColorMask(0,0,0,1);
2595 // this squares the result
2596 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2597 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2599 // second and third pass
2600 R_Mesh_ResetTextureState();
2601 // square alpha in framebuffer a few times to make it shiny
2602 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2603 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2604 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2607 memset(&m, 0, sizeof(m));
2608 m.tex[0] = R_GetTexture(glosstexture);
2609 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2610 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2611 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2612 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2613 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2614 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2615 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2616 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2617 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2618 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2622 // 2/0/0/2/2 2D combine blendsquare path
2623 memset(&m, 0, sizeof(m));
2624 m.tex[0] = R_GetTexture(normalmaptexture);
2625 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2626 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2627 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2628 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2629 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2630 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2631 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2632 m.pointer_texcoord_bufferobject[1] = 0;
2633 m.pointer_texcoord_bufferoffset[1] = 0;
2634 R_Mesh_TextureState(&m);
2635 GL_ColorMask(0,0,0,1);
2636 // this squares the result
2637 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2638 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2640 // second and third pass
2641 R_Mesh_ResetTextureState();
2642 // square alpha in framebuffer a few times to make it shiny
2643 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2644 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2645 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2648 memset(&m, 0, sizeof(m));
2649 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2650 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2651 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2652 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2653 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2654 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2655 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2656 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2658 m.texmatrix[1] = rsurface.entitytoattenuationz;
2659 R_Mesh_TextureState(&m);
2660 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2661 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2664 memset(&m, 0, sizeof(m));
2665 m.tex[0] = R_GetTexture(glosstexture);
2666 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2667 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2668 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2669 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2670 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2672 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2673 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2674 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2675 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2676 m.texmatrix[1] = rsurface.entitytolight;
2678 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2680 // this final code is shared
2681 R_Mesh_TextureState(&m);
2682 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);
2685 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)
2687 // ARB path (any Geforce, any Radeon)
2688 qboolean doambient = ambientscale > 0;
2689 qboolean dodiffuse = diffusescale > 0;
2690 qboolean dospecular = specularscale > 0;
2691 if (!doambient && !dodiffuse && !dospecular)
2693 R_Mesh_ColorPointer(NULL, 0, 0);
2695 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2697 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2701 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2703 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2708 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2710 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2713 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2716 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2723 int newnumtriangles;
2727 int maxtriangles = 4096;
2728 int newelements[4096*3];
2729 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2730 for (renders = 0;renders < 64;renders++)
2735 newnumtriangles = 0;
2737 // due to low fillrate on the cards this vertex lighting path is
2738 // designed for, we manually cull all triangles that do not
2739 // contain a lit vertex
2740 // this builds batches of triangles from multiple surfaces and
2741 // renders them at once
2742 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2744 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2746 if (newnumtriangles)
2748 newfirstvertex = min(newfirstvertex, e[0]);
2749 newlastvertex = max(newlastvertex, e[0]);
2753 newfirstvertex = e[0];
2754 newlastvertex = e[0];
2756 newfirstvertex = min(newfirstvertex, e[1]);
2757 newlastvertex = max(newlastvertex, e[1]);
2758 newfirstvertex = min(newfirstvertex, e[2]);
2759 newlastvertex = max(newlastvertex, e[2]);
2765 if (newnumtriangles >= maxtriangles)
2767 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2768 newnumtriangles = 0;
2774 if (newnumtriangles >= 1)
2776 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2779 // if we couldn't find any lit triangles, exit early
2782 // now reduce the intensity for the next overbright pass
2783 // we have to clamp to 0 here incase the drivers have improper
2784 // handling of negative colors
2785 // (some old drivers even have improper handling of >1 color)
2787 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2789 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2791 c[0] = max(0, c[0] - 1);
2792 c[1] = max(0, c[1] - 1);
2793 c[2] = max(0, c[2] - 1);
2805 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)
2807 // OpenGL 1.1 path (anything)
2808 float ambientcolorbase[3], diffusecolorbase[3];
2809 float ambientcolorpants[3], diffusecolorpants[3];
2810 float ambientcolorshirt[3], diffusecolorshirt[3];
2812 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2813 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2814 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2815 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2816 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2817 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2818 memset(&m, 0, sizeof(m));
2819 m.tex[0] = R_GetTexture(basetexture);
2820 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2821 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2822 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2823 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2824 if (r_textureunits.integer >= 2)
2827 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2828 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2829 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2830 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2831 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2832 if (r_textureunits.integer >= 3)
2834 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2835 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2836 m.texmatrix[2] = rsurface.entitytoattenuationz;
2837 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2838 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2839 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2842 R_Mesh_TextureState(&m);
2843 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2844 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2847 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2848 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2852 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2853 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2857 extern cvar_t gl_lightmaps;
2858 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)
2860 float ambientscale, diffusescale, specularscale;
2861 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2863 // calculate colors to render this texture with
2864 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2865 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2866 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2867 ambientscale = rsurface.rtlight->ambientscale;
2868 diffusescale = rsurface.rtlight->diffusescale;
2869 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2870 if (!r_shadow_usenormalmap.integer)
2872 ambientscale += 1.0f * diffusescale;
2876 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2878 RSurf_SetupDepthAndCulling();
2879 nmap = rsurface.texture->currentskinframe->nmap;
2880 if (gl_lightmaps.integer)
2881 nmap = r_texture_blanknormalmap;
2882 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2884 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2885 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2888 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2889 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2890 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2893 VectorClear(lightcolorpants);
2896 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2897 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2898 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2901 VectorClear(lightcolorshirt);
2902 switch (r_shadow_rendermode)
2904 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2905 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2906 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);
2908 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2909 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);
2911 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2912 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);
2914 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2915 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);
2918 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2924 switch (r_shadow_rendermode)
2926 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2927 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2928 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);
2930 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2931 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);
2933 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2934 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);
2936 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2937 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);
2940 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2946 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)
2948 matrix4x4_t tempmatrix = *matrix;
2949 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2951 // if this light has been compiled before, free the associated data
2952 R_RTLight_Uncompile(rtlight);
2954 // clear it completely to avoid any lingering data
2955 memset(rtlight, 0, sizeof(*rtlight));
2957 // copy the properties
2958 rtlight->matrix_lighttoworld = tempmatrix;
2959 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2960 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2961 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2962 VectorCopy(color, rtlight->color);
2963 rtlight->cubemapname[0] = 0;
2964 if (cubemapname && cubemapname[0])
2965 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2966 rtlight->shadow = shadow;
2967 rtlight->corona = corona;
2968 rtlight->style = style;
2969 rtlight->isstatic = isstatic;
2970 rtlight->coronasizescale = coronasizescale;
2971 rtlight->ambientscale = ambientscale;
2972 rtlight->diffusescale = diffusescale;
2973 rtlight->specularscale = specularscale;
2974 rtlight->flags = flags;
2976 // compute derived data
2977 //rtlight->cullradius = rtlight->radius;
2978 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2979 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2980 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2981 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2982 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2983 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2984 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2987 // compiles rtlight geometry
2988 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2989 void R_RTLight_Compile(rtlight_t *rtlight)
2992 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2993 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2994 entity_render_t *ent = r_refdef.scene.worldentity;
2995 dp_model_t *model = r_refdef.scene.worldmodel;
2996 unsigned char *data;
2999 // compile the light
3000 rtlight->compiled = true;
3001 rtlight->static_numleafs = 0;
3002 rtlight->static_numleafpvsbytes = 0;
3003 rtlight->static_leaflist = NULL;
3004 rtlight->static_leafpvs = NULL;
3005 rtlight->static_numsurfaces = 0;
3006 rtlight->static_surfacelist = NULL;
3007 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3008 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3009 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3010 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3011 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3012 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3014 if (model && model->GetLightInfo)
3016 // this variable must be set for the CompileShadowVolume code
3017 r_shadow_compilingrtlight = rtlight;
3018 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);
3019 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);
3020 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3021 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3022 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3023 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3024 rtlight->static_numsurfaces = numsurfaces;
3025 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3026 rtlight->static_numleafs = numleafs;
3027 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3028 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3029 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3030 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3031 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3032 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3033 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3034 if (rtlight->static_numsurfaces)
3035 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3036 if (rtlight->static_numleafs)
3037 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3038 if (rtlight->static_numleafpvsbytes)
3039 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3040 if (rtlight->static_numshadowtrispvsbytes)
3041 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3042 if (rtlight->static_numlighttrispvsbytes)
3043 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3044 if (model->CompileShadowVolume && rtlight->shadow)
3045 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3046 // now we're done compiling the rtlight
3047 r_shadow_compilingrtlight = NULL;
3051 // use smallest available cullradius - box radius or light radius
3052 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3053 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3055 shadowzpasstris = 0;
3056 if (rtlight->static_meshchain_shadow_zpass)
3057 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3058 shadowzpasstris += mesh->numtriangles;
3060 shadowzfailtris = 0;
3061 if (rtlight->static_meshchain_shadow_zfail)
3062 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3063 shadowzfailtris += mesh->numtriangles;
3066 if (rtlight->static_numlighttrispvsbytes)
3067 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3068 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3072 if (rtlight->static_numlighttrispvsbytes)
3073 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3074 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3077 if (developer.integer >= 10)
3078 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);
3081 void R_RTLight_Uncompile(rtlight_t *rtlight)
3083 if (rtlight->compiled)
3085 if (rtlight->static_meshchain_shadow_zpass)
3086 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3087 rtlight->static_meshchain_shadow_zpass = NULL;
3088 if (rtlight->static_meshchain_shadow_zfail)
3089 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3090 rtlight->static_meshchain_shadow_zfail = NULL;
3091 // these allocations are grouped
3092 if (rtlight->static_surfacelist)
3093 Mem_Free(rtlight->static_surfacelist);
3094 rtlight->static_numleafs = 0;
3095 rtlight->static_numleafpvsbytes = 0;
3096 rtlight->static_leaflist = NULL;
3097 rtlight->static_leafpvs = NULL;
3098 rtlight->static_numsurfaces = 0;
3099 rtlight->static_surfacelist = NULL;
3100 rtlight->static_numshadowtrispvsbytes = 0;
3101 rtlight->static_shadowtrispvs = NULL;
3102 rtlight->static_numlighttrispvsbytes = 0;
3103 rtlight->static_lighttrispvs = NULL;
3104 rtlight->compiled = false;
3108 void R_Shadow_UncompileWorldLights(void)
3112 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3113 for (lightindex = 0;lightindex < range;lightindex++)
3115 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3118 R_RTLight_Uncompile(&light->rtlight);
3122 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3126 // reset the count of frustum planes
3127 // see rsurface.rtlight_frustumplanes definition for how much this array
3129 rsurface.rtlight_numfrustumplanes = 0;
3131 // haven't implemented a culling path for ortho rendering
3132 if (!r_refdef.view.useperspective)
3134 // check if the light is on screen and copy the 4 planes if it is
3135 for (i = 0;i < 4;i++)
3136 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3139 for (i = 0;i < 4;i++)
3140 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3145 // generate a deformed frustum that includes the light origin, this is
3146 // used to cull shadow casting surfaces that can not possibly cast a
3147 // shadow onto the visible light-receiving surfaces, which can be a
3150 // if the light origin is onscreen the result will be 4 planes exactly
3151 // if the light origin is offscreen on only one axis the result will
3152 // be exactly 5 planes (split-side case)
3153 // if the light origin is offscreen on two axes the result will be
3154 // exactly 4 planes (stretched corner case)
3155 for (i = 0;i < 4;i++)
3157 // quickly reject standard frustum planes that put the light
3158 // origin outside the frustum
3159 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3162 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3164 // if all the standard frustum planes were accepted, the light is onscreen
3165 // otherwise we need to generate some more planes below...
3166 if (rsurface.rtlight_numfrustumplanes < 4)
3168 // at least one of the stock frustum planes failed, so we need to
3169 // create one or two custom planes to enclose the light origin
3170 for (i = 0;i < 4;i++)
3172 // create a plane using the view origin and light origin, and a
3173 // single point from the frustum corner set
3174 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3175 VectorNormalize(plane.normal);
3176 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3177 // see if this plane is backwards and flip it if so
3178 for (j = 0;j < 4;j++)
3179 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3183 VectorNegate(plane.normal, plane.normal);
3185 // flipped plane, test again to see if it is now valid
3186 for (j = 0;j < 4;j++)
3187 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3189 // if the plane is still not valid, then it is dividing the
3190 // frustum and has to be rejected
3194 // we have created a valid plane, compute extra info
3195 PlaneClassify(&plane);
3197 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3199 // if we've found 5 frustum planes then we have constructed a
3200 // proper split-side case and do not need to keep searching for
3201 // planes to enclose the light origin
3202 if (rsurface.rtlight_numfrustumplanes == 5)
3210 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3212 plane = rsurface.rtlight_frustumplanes[i];
3213 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));
3218 // now add the light-space box planes if the light box is rotated, as any
3219 // caster outside the oriented light box is irrelevant (even if it passed
3220 // the worldspace light box, which is axial)
3221 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3223 for (i = 0;i < 6;i++)
3227 v[i >> 1] = (i & 1) ? -1 : 1;
3228 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3229 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3230 plane.dist = VectorNormalizeLength(plane.normal);
3231 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3232 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3238 // add the world-space reduced box planes
3239 for (i = 0;i < 6;i++)
3241 VectorClear(plane.normal);
3242 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3243 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3244 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3253 // reduce all plane distances to tightly fit the rtlight cull box, which
3255 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3256 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3257 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3258 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3259 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3260 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3261 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3262 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3263 oldnum = rsurface.rtlight_numfrustumplanes;
3264 rsurface.rtlight_numfrustumplanes = 0;
3265 for (j = 0;j < oldnum;j++)
3267 // find the nearest point on the box to this plane
3268 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3269 for (i = 1;i < 8;i++)
3271 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3272 if (bestdist > dist)
3275 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);
3276 // if the nearest point is near or behind the plane, we want this
3277 // plane, otherwise the plane is useless as it won't cull anything
3278 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3280 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3281 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3288 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3293 int surfacelistindex;
3294 msurface_t *surface;
3296 RSurf_ActiveWorldEntity();
3297 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3299 if (r_refdef.scene.worldentity->model)
3300 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3301 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3305 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3308 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3309 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3310 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3311 for (;mesh;mesh = mesh->next)
3313 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3314 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3315 GL_LockArrays(0, mesh->numverts);
3316 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3318 // increment stencil if frontface is infront of depthbuffer
3319 GL_CullFace(r_refdef.view.cullface_back);
3320 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3321 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3322 // decrement stencil if backface is infront of depthbuffer
3323 GL_CullFace(r_refdef.view.cullface_front);
3324 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3326 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3328 // decrement stencil if backface is behind depthbuffer
3329 GL_CullFace(r_refdef.view.cullface_front);
3330 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3331 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3332 // increment stencil if frontface is behind depthbuffer
3333 GL_CullFace(r_refdef.view.cullface_back);
3334 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3336 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3337 GL_LockArrays(0, 0);
3341 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3343 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3344 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3346 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3347 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3348 if (CHECKPVSBIT(trispvs, t))
3349 shadowmarklist[numshadowmark++] = t;
3351 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);
3353 else if (numsurfaces)
3354 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3356 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3359 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3361 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3362 vec_t relativeshadowradius;
3363 RSurf_ActiveModelEntity(ent, false, false);
3364 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3365 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3366 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3367 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3368 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3369 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3370 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3371 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3372 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3373 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3375 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3376 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3379 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3381 // set up properties for rendering light onto this entity
3382 RSurf_ActiveModelEntity(ent, true, true);
3383 GL_AlphaTest(false);
3384 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3385 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3386 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3387 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3388 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3389 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3392 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3394 if (!r_refdef.scene.worldmodel->DrawLight)
3397 // set up properties for rendering light onto this entity
3398 RSurf_ActiveWorldEntity();
3399 GL_AlphaTest(false);
3400 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3401 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3402 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3403 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3404 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3405 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3407 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3409 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3412 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3414 dp_model_t *model = ent->model;
3415 if (!model->DrawLight)
3418 R_Shadow_SetupEntityLight(ent);
3420 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3422 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3426 {{ 0, 0, 0}, "px", true, true, true},
3427 {{ 0, 90, 0}, "py", false, true, false},
3428 {{ 0, 180, 0}, "nx", false, false, true},
3429 {{ 0, 270, 0}, "ny", true, false, false},
3430 {{-90, 180, 0}, "pz", false, false, true},
3431 {{ 90, 180, 0}, "nz", false, false, true}
3434 static const double shadowviewmat16[6][4][4] =
3474 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3478 int numleafs, numsurfaces;
3479 int *leaflist, *surfacelist;
3480 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3481 int numlightentities;
3482 int numlightentities_noselfshadow;
3483 int numshadowentities;
3484 int numshadowentities_noselfshadow;
3485 static entity_render_t *lightentities[MAX_EDICTS];
3486 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3487 static entity_render_t *shadowentities[MAX_EDICTS];
3488 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3489 vec3_t nearestpoint;
3491 qboolean castshadows;
3494 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3495 // skip lights that are basically invisible (color 0 0 0)
3496 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3499 // loading is done before visibility checks because loading should happen
3500 // all at once at the start of a level, not when it stalls gameplay.
3501 // (especially important to benchmarks)
3503 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3504 R_RTLight_Compile(rtlight);
3506 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3508 // look up the light style value at this time
3509 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3510 VectorScale(rtlight->color, f, rtlight->currentcolor);
3512 if (rtlight->selected)
3514 f = 2 + sin(realtime * M_PI * 4.0);
3515 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3519 // if lightstyle is currently off, don't draw the light
3520 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3523 // if the light box is offscreen, skip it
3524 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3527 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3528 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3530 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3532 // compiled light, world available and can receive realtime lighting
3533 // retrieve leaf information
3534 numleafs = rtlight->static_numleafs;
3535 leaflist = rtlight->static_leaflist;
3536 leafpvs = rtlight->static_leafpvs;
3537 numsurfaces = rtlight->static_numsurfaces;
3538 surfacelist = rtlight->static_surfacelist;
3539 shadowtrispvs = rtlight->static_shadowtrispvs;
3540 lighttrispvs = rtlight->static_lighttrispvs;
3542 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3544 // dynamic light, world available and can receive realtime lighting
3545 // calculate lit surfaces and leafs
3546 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);
3547 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);
3548 leaflist = r_shadow_buffer_leaflist;
3549 leafpvs = r_shadow_buffer_leafpvs;
3550 surfacelist = r_shadow_buffer_surfacelist;
3551 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3552 lighttrispvs = r_shadow_buffer_lighttrispvs;
3553 // if the reduced leaf bounds are offscreen, skip it
3554 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3565 shadowtrispvs = NULL;
3566 lighttrispvs = NULL;
3568 // check if light is illuminating any visible leafs
3571 for (i = 0;i < numleafs;i++)
3572 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3577 // set up a scissor rectangle for this light
3578 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3581 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3583 // make a list of lit entities and shadow casting entities
3584 numlightentities = 0;
3585 numlightentities_noselfshadow = 0;
3586 numshadowentities = 0;
3587 numshadowentities_noselfshadow = 0;
3588 // add dynamic entities that are lit by the light
3589 if (r_drawentities.integer)
3591 for (i = 0;i < r_refdef.scene.numentities;i++)
3594 entity_render_t *ent = r_refdef.scene.entities[i];
3596 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3598 // skip the object entirely if it is not within the valid
3599 // shadow-casting region (which includes the lit region)
3600 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3602 if (!(model = ent->model))
3604 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3606 // this entity wants to receive light, is visible, and is
3607 // inside the light box
3608 // TODO: check if the surfaces in the model can receive light
3609 // so now check if it's in a leaf seen by the light
3610 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))
3612 if (ent->flags & RENDER_NOSELFSHADOW)
3613 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3615 lightentities[numlightentities++] = ent;
3616 // since it is lit, it probably also casts a shadow...
3617 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3618 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3619 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3621 // note: exterior models without the RENDER_NOSELFSHADOW
3622 // flag still create a RENDER_NOSELFSHADOW shadow but
3623 // are lit normally, this means that they are
3624 // self-shadowing but do not shadow other
3625 // RENDER_NOSELFSHADOW entities such as the gun
3626 // (very weird, but keeps the player shadow off the gun)
3627 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3628 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3630 shadowentities[numshadowentities++] = ent;
3633 else if (ent->flags & RENDER_SHADOW)
3635 // this entity is not receiving light, but may still need to
3637 // TODO: check if the surfaces in the model can cast shadow
3638 // now check if it is in a leaf seen by the light
3639 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))
3641 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3642 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3643 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3645 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3646 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3648 shadowentities[numshadowentities++] = ent;
3654 // return if there's nothing at all to light
3655 if (!numlightentities && !numsurfaces)
3658 // don't let sound skip if going slow
3659 if (r_refdef.scene.extraupdate)
3662 // make this the active rtlight for rendering purposes
3663 R_Shadow_RenderMode_ActiveLight(rtlight);
3664 // count this light in the r_speeds
3665 r_refdef.stats.lights++;
3667 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3669 // optionally draw visible shape of the shadow volumes
3670 // for performance analysis by level designers
3671 R_Shadow_RenderMode_VisibleShadowVolumes();
3673 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3674 for (i = 0;i < numshadowentities;i++)
3675 R_Shadow_DrawEntityShadow(shadowentities[i]);
3676 for (i = 0;i < numshadowentities_noselfshadow;i++)
3677 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3680 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3682 // optionally draw the illuminated areas
3683 // for performance analysis by level designers
3684 R_Shadow_RenderMode_VisibleLighting(false, false);
3686 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3687 for (i = 0;i < numlightentities;i++)
3688 R_Shadow_DrawEntityLight(lightentities[i]);
3689 for (i = 0;i < numlightentities_noselfshadow;i++)
3690 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3693 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3695 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3696 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3697 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3698 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3699 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3700 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3702 if (castshadows && r_shadow_shadowmapping.integer >= 1 && r_shadow_shadowmapping.integer <= 3 && r_glsl.integer && gl_support_fragment_shader)
3707 r_shadow_shadowmaplod = 0;
3708 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3709 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3710 r_shadow_shadowmaplod = i;
3713 if (r_shadow_shadowmapping.integer == 3)
3714 size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod;
3715 size = bound(1, size, 2048);
3717 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3719 // render shadow casters into 6 sided depth texture
3720 for (side = 0;side < 6;side++)
3722 R_Shadow_RenderMode_ShadowMap(side, true, size);
3724 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3725 for (i = 0;i < numshadowentities;i++)
3726 R_Shadow_DrawEntityShadow(shadowentities[i]);
3729 if (numlightentities_noselfshadow)
3731 // render lighting using the depth texture as shadowmap
3732 // draw lighting in the unmasked areas
3733 R_Shadow_RenderMode_Lighting(false, false, true);
3734 for (i = 0;i < numlightentities_noselfshadow;i++)
3735 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3738 // render shadow casters into 6 sided depth texture
3739 for (side = 0;side < 6;side++)
3741 R_Shadow_RenderMode_ShadowMap(side, false, size);
3742 for (i = 0;i < numshadowentities_noselfshadow;i++)
3743 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3745 if (r_shadow_shadowmapping.integer == 1)
3747 int w = R_TextureWidth(r_shadow_shadowmap2dtexture);
3748 int h = R_TextureHeight(r_shadow_shadowmap2dtexture);
3749 static int once = true;
3752 unsigned char *blah = Z_Malloc(w*h*4);
3753 qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR
3754 FS_WriteFile("testshadowmap.bin", blah, w*h*4);
3762 // render lighting using the depth texture as shadowmap
3763 // draw lighting in the unmasked areas
3764 R_Shadow_RenderMode_Lighting(false, false, true);
3765 // draw lighting in the unmasked areas
3767 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3768 for (i = 0;i < numlightentities;i++)
3769 R_Shadow_DrawEntityLight(lightentities[i]);
3771 else if (castshadows && gl_stencil)
3773 // draw stencil shadow volumes to mask off pixels that are in shadow
3774 // so that they won't receive lighting
3775 R_Shadow_ClearStencil();
3777 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3778 for (i = 0;i < numshadowentities;i++)
3779 R_Shadow_DrawEntityShadow(shadowentities[i]);
3780 if (numlightentities_noselfshadow)
3782 // draw lighting in the unmasked areas
3783 R_Shadow_RenderMode_Lighting(true, false, false);
3784 for (i = 0;i < numlightentities_noselfshadow;i++)
3785 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3787 // optionally draw the illuminated areas
3788 // for performance analysis by level designers
3789 if (r_showlighting.integer && r_refdef.view.showdebug)
3791 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3792 for (i = 0;i < numlightentities_noselfshadow;i++)
3793 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3796 for (i = 0;i < numshadowentities_noselfshadow;i++)
3797 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3799 if (numsurfaces + numlightentities)
3801 // draw lighting in the unmasked areas
3802 R_Shadow_RenderMode_Lighting(true, false, false);
3804 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3805 for (i = 0;i < numlightentities;i++)
3806 R_Shadow_DrawEntityLight(lightentities[i]);
3811 if (numsurfaces + numlightentities)
3813 // draw lighting in the unmasked areas
3814 R_Shadow_RenderMode_Lighting(false, false, false);
3816 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3817 for (i = 0;i < numlightentities;i++)
3818 R_Shadow_DrawEntityLight(lightentities[i]);
3819 for (i = 0;i < numlightentities_noselfshadow;i++)
3820 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3825 void R_Shadow_DrawLightSprites(void);
3826 void R_ShadowVolumeLighting(qboolean visible)
3834 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer)
3835 R_Shadow_FreeShadowMaps();
3837 if (r_editlights.integer)
3838 R_Shadow_DrawLightSprites();
3840 R_Shadow_RenderMode_Begin();
3842 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3843 if (r_shadow_debuglight.integer >= 0)
3845 lightindex = r_shadow_debuglight.integer;
3846 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3847 if (light && (light->flags & flag))
3848 R_DrawRTLight(&light->rtlight, visible);
3852 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3853 for (lightindex = 0;lightindex < range;lightindex++)
3855 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3856 if (light && (light->flags & flag))
3857 R_DrawRTLight(&light->rtlight, visible);
3860 if (r_refdef.scene.rtdlight)
3861 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3862 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3864 R_Shadow_RenderMode_End();
3867 extern void R_SetupView(qboolean allowwaterclippingplane);
3868 extern cvar_t r_shadows;
3869 extern cvar_t r_shadows_darken;
3870 extern cvar_t r_shadows_drawafterrtlightning;
3871 extern cvar_t r_shadows_castfrombmodels;
3872 extern cvar_t r_shadows_throwdistance;
3873 extern cvar_t r_shadows_throwdirection;
3874 void R_DrawModelShadows(void)
3877 float relativethrowdistance;
3878 entity_render_t *ent;
3879 vec3_t relativelightorigin;
3880 vec3_t relativelightdirection;
3881 vec3_t relativeshadowmins, relativeshadowmaxs;
3882 vec3_t tmp, shadowdir;
3884 r_viewport_t viewport;
3886 if (!r_drawentities.integer || !gl_stencil)
3890 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3892 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3894 if (gl_ext_separatestencil.integer)
3896 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
3897 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
3899 else if (gl_ext_stenciltwoside.integer)
3901 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
3902 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
3906 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
3907 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
3911 if (r_shadows.integer == 2)
3913 Math_atov(r_shadows_throwdirection.string, shadowdir);
3914 VectorNormalize(shadowdir);
3917 R_Shadow_ClearStencil();
3919 for (i = 0;i < r_refdef.scene.numentities;i++)
3921 ent = r_refdef.scene.entities[i];
3923 // cast shadows from anything of the map (submodels are optional)
3924 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3926 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3927 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3928 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3929 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3930 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3933 if(ent->entitynumber != 0)
3935 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3936 int entnum, entnum2, recursion;
3937 entnum = entnum2 = ent->entitynumber;
3938 for(recursion = 32; recursion > 0; --recursion)
3940 entnum2 = cl.entities[entnum].state_current.tagentity;
3941 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3946 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3948 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3949 // transform into modelspace of OUR entity
3950 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3951 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3954 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3957 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3960 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3961 RSurf_ActiveModelEntity(ent, false, false);
3962 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3963 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3967 // not really the right mode, but this will disable any silly stencil features
3968 R_Shadow_RenderMode_VisibleLighting(true, true);
3970 // vertex coordinates for a quad that covers the screen exactly
3971 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3972 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3973 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3974 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3976 // set up ortho view for rendering this pass
3977 R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
3978 R_SetViewport(&viewport);
3979 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3980 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3981 GL_ScissorTest(true);
3982 R_Mesh_Matrix(&identitymatrix);
3983 R_Mesh_ResetTextureState();
3984 R_Mesh_VertexPointer(vertex3f, 0, 0);
3985 R_Mesh_ColorPointer(NULL, 0, 0);
3987 // set up a darkening blend on shadowed areas
3988 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3989 GL_DepthRange(0, 1);
3990 GL_DepthTest(false);
3991 GL_DepthMask(false);
3992 GL_PolygonOffset(0, 0);CHECKGLERROR
3993 GL_Color(0, 0, 0, r_shadows_darken.value);
3994 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3995 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3996 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3997 qglStencilMask(~0);CHECKGLERROR
3998 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3999 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4001 // apply the blend to the shadowed areas
4002 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4004 // restore the viewport
4005 R_SetViewport(&r_refdef.view.viewport);
4007 // restore other state to normal
4008 R_Shadow_RenderMode_End();
4011 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4014 vec3_t centerorigin;
4015 // if it's too close, skip it
4016 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4018 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4021 if (usequery && r_numqueries + 2 <= r_maxqueries)
4023 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4024 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4025 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4028 // 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
4029 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4030 qglDepthFunc(GL_ALWAYS);
4031 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);
4032 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4033 qglDepthFunc(GL_LEQUAL);
4034 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4035 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);
4036 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4039 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4042 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4045 GLint allpixels = 0, visiblepixels = 0;
4046 // now we have to check the query result
4047 if (rtlight->corona_queryindex_visiblepixels)
4050 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4051 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4053 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4054 if (visiblepixels < 1 || allpixels < 1)
4056 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4057 cscale *= rtlight->corona_visibility;
4061 // FIXME: these traces should scan all render entities instead of cl.world
4062 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4065 VectorScale(rtlight->color, cscale, color);
4066 if (VectorLength(color) > (1.0f / 256.0f))
4067 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);
4070 void R_DrawCoronas(void)
4078 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4080 if (r_waterstate.renderingscene)
4082 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4083 R_Mesh_Matrix(&identitymatrix);
4085 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4087 // check occlusion of coronas
4088 // use GL_ARB_occlusion_query if available
4089 // otherwise use raytraces
4091 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4094 GL_ColorMask(0,0,0,0);
4095 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4096 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4099 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4100 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4102 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4106 for (lightindex = 0;lightindex < range;lightindex++)
4108 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4111 rtlight = &light->rtlight;
4112 rtlight->corona_visibility = 0;
4113 rtlight->corona_queryindex_visiblepixels = 0;
4114 rtlight->corona_queryindex_allpixels = 0;
4115 if (!(rtlight->flags & flag))
4117 if (rtlight->corona <= 0)
4119 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4121 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4123 for (i = 0;i < r_refdef.scene.numlights;i++)
4125 rtlight = r_refdef.scene.lights[i];
4126 rtlight->corona_visibility = 0;
4127 rtlight->corona_queryindex_visiblepixels = 0;
4128 rtlight->corona_queryindex_allpixels = 0;
4129 if (!(rtlight->flags & flag))
4131 if (rtlight->corona <= 0)
4133 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4136 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4138 // now draw the coronas using the query data for intensity info
4139 for (lightindex = 0;lightindex < range;lightindex++)
4141 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4144 rtlight = &light->rtlight;
4145 if (rtlight->corona_visibility <= 0)
4147 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4149 for (i = 0;i < r_refdef.scene.numlights;i++)
4151 rtlight = r_refdef.scene.lights[i];
4152 if (rtlight->corona_visibility <= 0)
4154 if (gl_flashblend.integer)
4155 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4157 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4163 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4164 typedef struct suffixinfo_s
4167 qboolean flipx, flipy, flipdiagonal;
4170 static suffixinfo_t suffix[3][6] =
4173 {"px", false, false, false},
4174 {"nx", false, false, false},
4175 {"py", false, false, false},
4176 {"ny", false, false, false},
4177 {"pz", false, false, false},
4178 {"nz", false, false, false}
4181 {"posx", false, false, false},
4182 {"negx", false, false, false},
4183 {"posy", false, false, false},
4184 {"negy", false, false, false},
4185 {"posz", false, false, false},
4186 {"negz", false, false, false}
4189 {"rt", true, false, true},
4190 {"lf", false, true, true},
4191 {"ft", true, true, false},
4192 {"bk", false, false, false},
4193 {"up", true, false, true},
4194 {"dn", true, false, true}
4198 static int componentorder[4] = {0, 1, 2, 3};
4200 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4202 int i, j, cubemapsize;
4203 unsigned char *cubemappixels, *image_buffer;
4204 rtexture_t *cubemaptexture;
4206 // must start 0 so the first loadimagepixels has no requested width/height
4208 cubemappixels = NULL;
4209 cubemaptexture = NULL;
4210 // keep trying different suffix groups (posx, px, rt) until one loads
4211 for (j = 0;j < 3 && !cubemappixels;j++)
4213 // load the 6 images in the suffix group
4214 for (i = 0;i < 6;i++)
4216 // generate an image name based on the base and and suffix
4217 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4219 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4221 // an image loaded, make sure width and height are equal
4222 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4224 // if this is the first image to load successfully, allocate the cubemap memory
4225 if (!cubemappixels && image_width >= 1)
4227 cubemapsize = image_width;
4228 // note this clears to black, so unavailable sides are black
4229 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4231 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4233 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);
4236 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4238 Mem_Free(image_buffer);
4242 // if a cubemap loaded, upload it
4245 if (developer_loading.integer)
4246 Con_Printf("loading cubemap \"%s\"\n", basename);
4248 if (!r_shadow_filters_texturepool)
4249 r_shadow_filters_texturepool = R_AllocTexturePool();
4250 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4251 Mem_Free(cubemappixels);
4255 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4256 if (developer_loading.integer)
4258 Con_Printf("(tried tried images ");
4259 for (j = 0;j < 3;j++)
4260 for (i = 0;i < 6;i++)
4261 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4262 Con_Print(" and was unable to find any of them).\n");
4265 return cubemaptexture;
4268 rtexture_t *R_Shadow_Cubemap(const char *basename)
4271 for (i = 0;i < numcubemaps;i++)
4272 if (!strcasecmp(cubemaps[i].basename, basename))
4273 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4274 if (i >= MAX_CUBEMAPS)
4275 return r_texture_whitecube;
4277 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4278 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4279 return cubemaps[i].texture;
4282 void R_Shadow_FreeCubemaps(void)
4285 for (i = 0;i < numcubemaps;i++)
4287 if (developer_loading.integer)
4288 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4289 if (cubemaps[i].texture)
4290 R_FreeTexture(cubemaps[i].texture);
4294 R_FreeTexturePool(&r_shadow_filters_texturepool);
4297 dlight_t *R_Shadow_NewWorldLight(void)
4299 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4302 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)
4305 // validate parameters
4306 if (style < 0 || style >= MAX_LIGHTSTYLES)
4308 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4314 // copy to light properties
4315 VectorCopy(origin, light->origin);
4316 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4317 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4318 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4319 light->color[0] = max(color[0], 0);
4320 light->color[1] = max(color[1], 0);
4321 light->color[2] = max(color[2], 0);
4322 light->radius = max(radius, 0);
4323 light->style = style;
4324 light->shadow = shadowenable;
4325 light->corona = corona;
4326 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4327 light->coronasizescale = coronasizescale;
4328 light->ambientscale = ambientscale;
4329 light->diffusescale = diffusescale;
4330 light->specularscale = specularscale;
4331 light->flags = flags;
4333 // update renderable light data
4334 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4335 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);
4338 void R_Shadow_FreeWorldLight(dlight_t *light)
4340 if (r_shadow_selectedlight == light)
4341 r_shadow_selectedlight = NULL;
4342 R_RTLight_Uncompile(&light->rtlight);
4343 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4346 void R_Shadow_ClearWorldLights(void)
4350 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4351 for (lightindex = 0;lightindex < range;lightindex++)
4353 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4355 R_Shadow_FreeWorldLight(light);
4357 r_shadow_selectedlight = NULL;
4358 R_Shadow_FreeCubemaps();
4361 void R_Shadow_SelectLight(dlight_t *light)
4363 if (r_shadow_selectedlight)
4364 r_shadow_selectedlight->selected = false;
4365 r_shadow_selectedlight = light;
4366 if (r_shadow_selectedlight)
4367 r_shadow_selectedlight->selected = true;
4370 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4372 // this is never batched (there can be only one)
4373 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);
4376 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4383 // this is never batched (due to the ent parameter changing every time)
4384 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4385 const dlight_t *light = (dlight_t *)ent;
4388 VectorScale(light->color, intensity, spritecolor);
4389 if (VectorLength(spritecolor) < 0.1732f)
4390 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4391 if (VectorLength(spritecolor) > 1.0f)
4392 VectorNormalize(spritecolor);
4394 // draw light sprite
4395 if (light->cubemapname[0] && !light->shadow)
4396 pic = r_editlights_sprcubemapnoshadowlight;
4397 else if (light->cubemapname[0])
4398 pic = r_editlights_sprcubemaplight;
4399 else if (!light->shadow)
4400 pic = r_editlights_sprnoshadowlight;
4402 pic = r_editlights_sprlight;
4403 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);
4404 // draw selection sprite if light is selected
4405 if (light->selected)
4406 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);
4407 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4410 void R_Shadow_DrawLightSprites(void)
4414 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4415 for (lightindex = 0;lightindex < range;lightindex++)
4417 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4419 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4421 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4424 void R_Shadow_SelectLightInView(void)
4426 float bestrating, rating, temp[3];
4430 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4433 for (lightindex = 0;lightindex < range;lightindex++)
4435 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4438 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4439 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4442 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4443 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)
4445 bestrating = rating;
4450 R_Shadow_SelectLight(best);
4453 void R_Shadow_LoadWorldLights(void)
4455 int n, a, style, shadow, flags;
4456 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4457 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4458 if (cl.worldmodel == NULL)
4460 Con_Print("No map loaded.\n");
4463 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4464 strlcat (name, ".rtlights", sizeof (name));
4465 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4475 for (;COM_Parse(t, true) && strcmp(
4476 if (COM_Parse(t, true))
4478 if (com_token[0] == '!')
4481 origin[0] = atof(com_token+1);
4484 origin[0] = atof(com_token);
4489 while (*s && *s != '\n' && *s != '\r')
4495 // check for modifier flags
4502 #if _MSC_VER >= 1400
4503 #define sscanf sscanf_s
4505 cubemapname[sizeof(cubemapname)-1] = 0;
4506 #if MAX_QPATH != 128
4507 #error update this code if MAX_QPATH changes
4509 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
4510 #if _MSC_VER >= 1400
4511 , sizeof(cubemapname)
4513 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4516 flags = LIGHTFLAG_REALTIMEMODE;
4524 coronasizescale = 0.25f;
4526 VectorClear(angles);
4529 if (a < 9 || !strcmp(cubemapname, "\"\""))
4531 // remove quotes on cubemapname
4532 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4535 namelen = strlen(cubemapname) - 2;
4536 memmove(cubemapname, cubemapname + 1, namelen);
4537 cubemapname[namelen] = '\0';
4541 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);
4544 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4552 Con_Printf("invalid rtlights file \"%s\"\n", name);
4553 Mem_Free(lightsstring);
4557 void R_Shadow_SaveWorldLights(void)
4561 size_t bufchars, bufmaxchars;
4563 char name[MAX_QPATH];
4564 char line[MAX_INPUTLINE];
4565 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4566 // I hate lines which are 3 times my screen size :( --blub
4569 if (cl.worldmodel == NULL)
4571 Con_Print("No map loaded.\n");
4574 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4575 strlcat (name, ".rtlights", sizeof (name));
4576 bufchars = bufmaxchars = 0;
4578 for (lightindex = 0;lightindex < range;lightindex++)
4580 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4583 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4584 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);
4585 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4586 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]);
4588 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);
4589 if (bufchars + strlen(line) > bufmaxchars)
4591 bufmaxchars = bufchars + strlen(line) + 2048;
4593 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4597 memcpy(buf, oldbuf, bufchars);
4603 memcpy(buf + bufchars, line, strlen(line));
4604 bufchars += strlen(line);
4608 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4613 void R_Shadow_LoadLightsFile(void)
4616 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4617 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4618 if (cl.worldmodel == NULL)
4620 Con_Print("No map loaded.\n");
4623 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4624 strlcat (name, ".lights", sizeof (name));
4625 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4633 while (*s && *s != '\n' && *s != '\r')
4639 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);
4643 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);
4646 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4647 radius = bound(15, radius, 4096);
4648 VectorScale(color, (2.0f / (8388608.0f)), color);
4649 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4657 Con_Printf("invalid lights file \"%s\"\n", name);
4658 Mem_Free(lightsstring);
4662 // tyrlite/hmap2 light types in the delay field
4663 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4665 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4667 int entnum, style, islight, skin, pflags, effects, type, n;
4670 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4671 char key[256], value[MAX_INPUTLINE];
4673 if (cl.worldmodel == NULL)
4675 Con_Print("No map loaded.\n");
4678 // try to load a .ent file first
4679 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4680 strlcat (key, ".ent", sizeof (key));
4681 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4682 // and if that is not found, fall back to the bsp file entity string
4684 data = cl.worldmodel->brush.entities;
4687 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4689 type = LIGHTTYPE_MINUSX;
4690 origin[0] = origin[1] = origin[2] = 0;
4691 originhack[0] = originhack[1] = originhack[2] = 0;
4692 angles[0] = angles[1] = angles[2] = 0;
4693 color[0] = color[1] = color[2] = 1;
4694 light[0] = light[1] = light[2] = 1;light[3] = 300;
4695 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4705 if (!COM_ParseToken_Simple(&data, false, false))
4707 if (com_token[0] == '}')
4708 break; // end of entity
4709 if (com_token[0] == '_')
4710 strlcpy(key, com_token + 1, sizeof(key));
4712 strlcpy(key, com_token, sizeof(key));
4713 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4714 key[strlen(key)-1] = 0;
4715 if (!COM_ParseToken_Simple(&data, false, false))
4717 strlcpy(value, com_token, sizeof(value));
4719 // now that we have the key pair worked out...
4720 if (!strcmp("light", key))
4722 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4726 light[0] = vec[0] * (1.0f / 256.0f);
4727 light[1] = vec[0] * (1.0f / 256.0f);
4728 light[2] = vec[0] * (1.0f / 256.0f);
4734 light[0] = vec[0] * (1.0f / 255.0f);
4735 light[1] = vec[1] * (1.0f / 255.0f);
4736 light[2] = vec[2] * (1.0f / 255.0f);
4740 else if (!strcmp("delay", key))
4742 else if (!strcmp("origin", key))
4743 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4744 else if (!strcmp("angle", key))
4745 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4746 else if (!strcmp("angles", key))
4747 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4748 else if (!strcmp("color", key))
4749 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4750 else if (!strcmp("wait", key))
4751 fadescale = atof(value);
4752 else if (!strcmp("classname", key))
4754 if (!strncmp(value, "light", 5))
4757 if (!strcmp(value, "light_fluoro"))
4762 overridecolor[0] = 1;
4763 overridecolor[1] = 1;
4764 overridecolor[2] = 1;
4766 if (!strcmp(value, "light_fluorospark"))
4771 overridecolor[0] = 1;
4772 overridecolor[1] = 1;
4773 overridecolor[2] = 1;
4775 if (!strcmp(value, "light_globe"))
4780 overridecolor[0] = 1;
4781 overridecolor[1] = 0.8;
4782 overridecolor[2] = 0.4;
4784 if (!strcmp(value, "light_flame_large_yellow"))
4789 overridecolor[0] = 1;
4790 overridecolor[1] = 0.5;
4791 overridecolor[2] = 0.1;
4793 if (!strcmp(value, "light_flame_small_yellow"))
4798 overridecolor[0] = 1;
4799 overridecolor[1] = 0.5;
4800 overridecolor[2] = 0.1;
4802 if (!strcmp(value, "light_torch_small_white"))
4807 overridecolor[0] = 1;
4808 overridecolor[1] = 0.5;
4809 overridecolor[2] = 0.1;
4811 if (!strcmp(value, "light_torch_small_walltorch"))
4816 overridecolor[0] = 1;
4817 overridecolor[1] = 0.5;
4818 overridecolor[2] = 0.1;
4822 else if (!strcmp("style", key))
4823 style = atoi(value);
4824 else if (!strcmp("skin", key))
4825 skin = (int)atof(value);
4826 else if (!strcmp("pflags", key))
4827 pflags = (int)atof(value);
4828 else if (!strcmp("effects", key))
4829 effects = (int)atof(value);
4830 else if (cl.worldmodel->type == mod_brushq3)
4832 if (!strcmp("scale", key))
4833 lightscale = atof(value);
4834 if (!strcmp("fade", key))
4835 fadescale = atof(value);
4840 if (lightscale <= 0)
4844 if (color[0] == color[1] && color[0] == color[2])
4846 color[0] *= overridecolor[0];
4847 color[1] *= overridecolor[1];
4848 color[2] *= overridecolor[2];
4850 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4851 color[0] = color[0] * light[0];
4852 color[1] = color[1] * light[1];
4853 color[2] = color[2] * light[2];
4856 case LIGHTTYPE_MINUSX:
4858 case LIGHTTYPE_RECIPX:
4860 VectorScale(color, (1.0f / 16.0f), color);
4862 case LIGHTTYPE_RECIPXX:
4864 VectorScale(color, (1.0f / 16.0f), color);
4867 case LIGHTTYPE_NONE:
4871 case LIGHTTYPE_MINUSXX:
4874 VectorAdd(origin, originhack, origin);
4876 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);
4879 Mem_Free(entfiledata);
4883 void R_Shadow_SetCursorLocationForView(void)
4886 vec3_t dest, endpos;
4888 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4889 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4890 if (trace.fraction < 1)
4892 dist = trace.fraction * r_editlights_cursordistance.value;
4893 push = r_editlights_cursorpushback.value;
4897 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4898 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4902 VectorClear( endpos );
4904 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4905 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4906 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4909 void R_Shadow_UpdateWorldLightSelection(void)
4911 if (r_editlights.integer)
4913 R_Shadow_SetCursorLocationForView();
4914 R_Shadow_SelectLightInView();
4917 R_Shadow_SelectLight(NULL);
4920 void R_Shadow_EditLights_Clear_f(void)
4922 R_Shadow_ClearWorldLights();
4925 void R_Shadow_EditLights_Reload_f(void)
4929 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4930 R_Shadow_ClearWorldLights();
4931 R_Shadow_LoadWorldLights();
4932 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4934 R_Shadow_LoadLightsFile();
4935 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4936 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4940 void R_Shadow_EditLights_Save_f(void)
4944 R_Shadow_SaveWorldLights();
4947 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4949 R_Shadow_ClearWorldLights();
4950 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4953 void R_Shadow_EditLights_ImportLightsFile_f(void)
4955 R_Shadow_ClearWorldLights();
4956 R_Shadow_LoadLightsFile();
4959 void R_Shadow_EditLights_Spawn_f(void)
4962 if (!r_editlights.integer)
4964 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4967 if (Cmd_Argc() != 1)
4969 Con_Print("r_editlights_spawn does not take parameters\n");
4972 color[0] = color[1] = color[2] = 1;
4973 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4976 void R_Shadow_EditLights_Edit_f(void)
4978 vec3_t origin, angles, color;
4979 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4980 int style, shadows, flags, normalmode, realtimemode;
4981 char cubemapname[MAX_INPUTLINE];
4982 if (!r_editlights.integer)
4984 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4987 if (!r_shadow_selectedlight)
4989 Con_Print("No selected light.\n");
4992 VectorCopy(r_shadow_selectedlight->origin, origin);
4993 VectorCopy(r_shadow_selectedlight->angles, angles);
4994 VectorCopy(r_shadow_selectedlight->color, color);
4995 radius = r_shadow_selectedlight->radius;
4996 style = r_shadow_selectedlight->style;
4997 if (r_shadow_selectedlight->cubemapname)
4998 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5001 shadows = r_shadow_selectedlight->shadow;
5002 corona = r_shadow_selectedlight->corona;
5003 coronasizescale = r_shadow_selectedlight->coronasizescale;
5004 ambientscale = r_shadow_selectedlight->ambientscale;
5005 diffusescale = r_shadow_selectedlight->diffusescale;
5006 specularscale = r_shadow_selectedlight->specularscale;
5007 flags = r_shadow_selectedlight->flags;
5008 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5009 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5010 if (!strcmp(Cmd_Argv(1), "origin"))
5012 if (Cmd_Argc() != 5)
5014 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5017 origin[0] = atof(Cmd_Argv(2));
5018 origin[1] = atof(Cmd_Argv(3));
5019 origin[2] = atof(Cmd_Argv(4));
5021 else if (!strcmp(Cmd_Argv(1), "originx"))
5023 if (Cmd_Argc() != 3)
5025 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5028 origin[0] = atof(Cmd_Argv(2));
5030 else if (!strcmp(Cmd_Argv(1), "originy"))
5032 if (Cmd_Argc() != 3)
5034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5037 origin[1] = atof(Cmd_Argv(2));
5039 else if (!strcmp(Cmd_Argv(1), "originz"))
5041 if (Cmd_Argc() != 3)
5043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5046 origin[2] = atof(Cmd_Argv(2));
5048 else if (!strcmp(Cmd_Argv(1), "move"))
5050 if (Cmd_Argc() != 5)
5052 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5055 origin[0] += atof(Cmd_Argv(2));
5056 origin[1] += atof(Cmd_Argv(3));
5057 origin[2] += atof(Cmd_Argv(4));
5059 else if (!strcmp(Cmd_Argv(1), "movex"))
5061 if (Cmd_Argc() != 3)
5063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5066 origin[0] += atof(Cmd_Argv(2));
5068 else if (!strcmp(Cmd_Argv(1), "movey"))
5070 if (Cmd_Argc() != 3)
5072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5075 origin[1] += atof(Cmd_Argv(2));
5077 else if (!strcmp(Cmd_Argv(1), "movez"))
5079 if (Cmd_Argc() != 3)
5081 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5084 origin[2] += atof(Cmd_Argv(2));
5086 else if (!strcmp(Cmd_Argv(1), "angles"))
5088 if (Cmd_Argc() != 5)
5090 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5093 angles[0] = atof(Cmd_Argv(2));
5094 angles[1] = atof(Cmd_Argv(3));
5095 angles[2] = atof(Cmd_Argv(4));
5097 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5099 if (Cmd_Argc() != 3)
5101 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5104 angles[0] = atof(Cmd_Argv(2));
5106 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5108 if (Cmd_Argc() != 3)
5110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5113 angles[1] = atof(Cmd_Argv(2));
5115 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5117 if (Cmd_Argc() != 3)
5119 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5122 angles[2] = atof(Cmd_Argv(2));
5124 else if (!strcmp(Cmd_Argv(1), "color"))
5126 if (Cmd_Argc() != 5)
5128 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5131 color[0] = atof(Cmd_Argv(2));
5132 color[1] = atof(Cmd_Argv(3));
5133 color[2] = atof(Cmd_Argv(4));
5135 else if (!strcmp(Cmd_Argv(1), "radius"))
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), "colorscale"))
5146 if (Cmd_Argc() == 3)
5148 double scale = atof(Cmd_Argv(2));
5155 if (Cmd_Argc() != 5)
5157 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5160 color[0] *= atof(Cmd_Argv(2));
5161 color[1] *= atof(Cmd_Argv(3));
5162 color[2] *= atof(Cmd_Argv(4));
5165 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5167 if (Cmd_Argc() != 3)
5169 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5172 radius *= atof(Cmd_Argv(2));
5174 else if (!strcmp(Cmd_Argv(1), "style"))
5176 if (Cmd_Argc() != 3)
5178 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5181 style = atoi(Cmd_Argv(2));
5183 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5187 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5190 if (Cmd_Argc() == 3)
5191 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5195 else if (!strcmp(Cmd_Argv(1), "shadows"))
5197 if (Cmd_Argc() != 3)
5199 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5202 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5204 else if (!strcmp(Cmd_Argv(1), "corona"))
5206 if (Cmd_Argc() != 3)
5208 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5211 corona = atof(Cmd_Argv(2));
5213 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5215 if (Cmd_Argc() != 3)
5217 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5220 coronasizescale = atof(Cmd_Argv(2));
5222 else if (!strcmp(Cmd_Argv(1), "ambient"))
5224 if (Cmd_Argc() != 3)
5226 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5229 ambientscale = atof(Cmd_Argv(2));
5231 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5233 if (Cmd_Argc() != 3)
5235 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5238 diffusescale = atof(Cmd_Argv(2));
5240 else if (!strcmp(Cmd_Argv(1), "specular"))
5242 if (Cmd_Argc() != 3)
5244 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5247 specularscale = atof(Cmd_Argv(2));
5249 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5251 if (Cmd_Argc() != 3)
5253 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5256 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5258 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5260 if (Cmd_Argc() != 3)
5262 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5265 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5269 Con_Print("usage: r_editlights_edit [property] [value]\n");
5270 Con_Print("Selected light's properties:\n");
5271 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5272 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5273 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5274 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5275 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5276 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5277 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5278 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5279 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5280 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5281 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5282 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5283 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5284 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5287 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5288 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5291 void R_Shadow_EditLights_EditAll_f(void)
5297 if (!r_editlights.integer)
5299 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5303 // EditLights doesn't seem to have a "remove" command or something so:
5304 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5305 for (lightindex = 0;lightindex < range;lightindex++)
5307 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5310 R_Shadow_SelectLight(light);
5311 R_Shadow_EditLights_Edit_f();
5315 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5317 int lightnumber, lightcount;
5318 size_t lightindex, range;
5322 if (!r_editlights.integer)
5324 x = vid_conwidth.value - 240;
5326 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5329 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5330 for (lightindex = 0;lightindex < range;lightindex++)
5332 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5335 if (light == r_shadow_selectedlight)
5336 lightnumber = lightindex;
5339 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;
5340 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;
5342 if (r_shadow_selectedlight == NULL)
5344 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;
5345 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;
5346 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;
5347 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;
5348 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;
5349 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;
5350 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;
5351 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;
5352 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;
5353 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;
5354 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;
5355 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;
5356 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;
5357 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;
5358 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;
5361 void R_Shadow_EditLights_ToggleShadow_f(void)
5363 if (!r_editlights.integer)
5365 Con_Print("Cannot spawn 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_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);
5376 void R_Shadow_EditLights_ToggleCorona_f(void)
5378 if (!r_editlights.integer)
5380 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5383 if (!r_shadow_selectedlight)
5385 Con_Print("No selected light.\n");
5388 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);
5391 void R_Shadow_EditLights_Remove_f(void)
5393 if (!r_editlights.integer)
5395 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5398 if (!r_shadow_selectedlight)
5400 Con_Print("No selected light.\n");
5403 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5404 r_shadow_selectedlight = NULL;
5407 void R_Shadow_EditLights_Help_f(void)
5410 "Documentation on r_editlights system:\n"
5412 "r_editlights : enable/disable editing mode\n"
5413 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5414 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5415 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5416 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5417 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5419 "r_editlights_help : this help\n"
5420 "r_editlights_clear : remove all lights\n"
5421 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5422 "r_editlights_save : save to .rtlights file\n"
5423 "r_editlights_spawn : create a light with default settings\n"
5424 "r_editlights_edit command : edit selected light - more documentation below\n"
5425 "r_editlights_remove : remove selected light\n"
5426 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5427 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5428 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5430 "origin x y z : set light location\n"
5431 "originx x: set x component of light location\n"
5432 "originy y: set y component of light location\n"
5433 "originz z: set z component of light location\n"
5434 "move x y z : adjust light location\n"
5435 "movex x: adjust x component of light location\n"
5436 "movey y: adjust y component of light location\n"
5437 "movez z: adjust z component of light location\n"
5438 "angles x y z : set light angles\n"
5439 "anglesx x: set x component of light angles\n"
5440 "anglesy y: set y component of light angles\n"
5441 "anglesz z: set z component of light angles\n"
5442 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5443 "radius radius : set radius (size) of light\n"
5444 "colorscale grey : multiply color of light (1 does nothing)\n"
5445 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5446 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5447 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5448 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5449 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5450 "shadows 1/0 : turn on/off shadows\n"
5451 "corona n : set corona intensity\n"
5452 "coronasize n : set corona size (0-1)\n"
5453 "ambient n : set ambient intensity (0-1)\n"
5454 "diffuse n : set diffuse intensity (0-1)\n"
5455 "specular n : set specular intensity (0-1)\n"
5456 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5457 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5458 "<nothing> : print light properties to console\n"
5462 void R_Shadow_EditLights_CopyInfo_f(void)
5464 if (!r_editlights.integer)
5466 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5469 if (!r_shadow_selectedlight)
5471 Con_Print("No selected light.\n");
5474 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5475 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5476 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5477 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5478 if (r_shadow_selectedlight->cubemapname)
5479 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5481 r_shadow_bufferlight.cubemapname[0] = 0;
5482 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5483 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5484 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5485 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5486 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5487 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5488 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5491 void R_Shadow_EditLights_PasteInfo_f(void)
5493 if (!r_editlights.integer)
5495 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5498 if (!r_shadow_selectedlight)
5500 Con_Print("No selected light.\n");
5503 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);
5506 void R_Shadow_EditLights_Init(void)
5508 Cvar_RegisterVariable(&r_editlights);
5509 Cvar_RegisterVariable(&r_editlights_cursordistance);
5510 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5511 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5512 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5513 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5514 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5515 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5516 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)");
5517 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5518 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5519 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5520 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)");
5521 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5522 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5523 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5524 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5525 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5526 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5527 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)");
5533 =============================================================================
5537 =============================================================================
5540 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5542 VectorClear(diffusecolor);
5543 VectorClear(diffusenormal);
5545 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5547 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5548 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5551 VectorSet(ambientcolor, 1, 1, 1);
5558 for (i = 0;i < r_refdef.scene.numlights;i++)
5560 light = r_refdef.scene.lights[i];
5561 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5562 f = 1 - VectorLength2(v);
5563 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5564 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);