3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
162 R_SHADOW_RENDERMODE_SHADOWMAP2D,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 float r_shadow_shadowmap_texturescale[4];
175 float r_shadow_shadowmap_parameters[4];
176 int r_shadow_drawbuffer;
177 int r_shadow_readbuffer;
178 GLuint r_shadow_fborectangle;
179 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
180 GLuint r_shadow_fbo2d;
181 int r_shadow_shadowmode;
182 int r_shadow_shadowmapvsdct;
183 int r_shadow_shadowmapmaxsize;
184 int r_shadow_shadowmapfilter;
185 int r_shadow_shadowmapborder;
186 int r_shadow_lightscissor[4];
188 int maxshadowtriangles;
191 int maxshadowvertices;
192 float *shadowvertex3f;
205 int r_shadow_buffer_numleafpvsbytes;
206 unsigned char *r_shadow_buffer_visitingleafpvs;
207 unsigned char *r_shadow_buffer_leafpvs;
208 int *r_shadow_buffer_leaflist;
210 int r_shadow_buffer_numsurfacepvsbytes;
211 unsigned char *r_shadow_buffer_surfacepvs;
212 int *r_shadow_buffer_surfacelist;
214 int r_shadow_buffer_numshadowtrispvsbytes;
215 unsigned char *r_shadow_buffer_shadowtrispvs;
216 int r_shadow_buffer_numlighttrispvsbytes;
217 unsigned char *r_shadow_buffer_lighttrispvs;
219 rtexturepool_t *r_shadow_texturepool;
220 rtexture_t *r_shadow_attenuationgradienttexture;
221 rtexture_t *r_shadow_attenuation2dtexture;
222 rtexture_t *r_shadow_attenuation3dtexture;
223 rtexture_t *r_shadow_lightcorona;
224 rtexture_t *r_shadow_shadowmaprectangletexture;
225 rtexture_t *r_shadow_shadowmap2dtexture;
226 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
227 rtexture_t *r_shadow_shadowmapcubeprojectiontexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
228 int r_shadow_shadowmapsize; // changes for each light based on distance
229 int r_shadow_shadowmaplod; // changes for each light based on distance
231 // lights are reloaded when this changes
232 char r_shadow_mapname[MAX_QPATH];
234 // used only for light filters (cubemaps)
235 rtexturepool_t *r_shadow_filters_texturepool;
237 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"};
238 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"};
239 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
240 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
241 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)"};
242 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"};
243 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
244 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
245 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
246 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
247 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
248 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
249 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
250 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
251 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
252 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)"};
253 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
254 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
255 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
256 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
257 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)"};
258 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"};
259 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
260 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
261 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"};
262 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
263 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
264 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)"};
265 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"};
266 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
267 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
268 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
269 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
270 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
271 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
272 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
273 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
274 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
275 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
276 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
277 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)"};
278 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)"};
279 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
280 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"};
281 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
282 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
283 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
284 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
285 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
286 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
287 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
288 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
289 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
290 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
292 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
293 #define ATTENTABLESIZE 256
294 // 1D gradient, 2D circle and 3D sphere attenuation textures
295 #define ATTEN1DSIZE 32
296 #define ATTEN2DSIZE 64
297 #define ATTEN3DSIZE 32
299 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
300 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
301 static float r_shadow_attentable[ATTENTABLESIZE+1];
303 rtlight_t *r_shadow_compilingrtlight;
304 static memexpandablearray_t r_shadow_worldlightsarray;
305 dlight_t *r_shadow_selectedlight;
306 dlight_t r_shadow_bufferlight;
307 vec3_t r_editlights_cursorlocation;
309 extern int con_vislines;
311 typedef struct cubemapinfo_s
318 #define MAX_CUBEMAPS 256
319 static int numcubemaps;
320 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
322 void R_Shadow_UncompileWorldLights(void);
323 void R_Shadow_ClearWorldLights(void);
324 void R_Shadow_SaveWorldLights(void);
325 void R_Shadow_LoadWorldLights(void);
326 void R_Shadow_LoadLightsFile(void);
327 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
328 void R_Shadow_EditLights_Reload_f(void);
329 void R_Shadow_ValidateCvars(void);
330 static void R_Shadow_MakeTextures(void);
332 // VorteX: custom editor light sprites
333 #define EDLIGHTSPRSIZE 8
334 cachepic_t *r_editlights_sprcursor;
335 cachepic_t *r_editlights_sprlight;
336 cachepic_t *r_editlights_sprnoshadowlight;
337 cachepic_t *r_editlights_sprcubemaplight;
338 cachepic_t *r_editlights_sprcubemapnoshadowlight;
339 cachepic_t *r_editlights_sprselection;
341 void R_Shadow_FreeShadowMaps(void)
345 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
346 r_shadow_shadowmode = r_shadow_shadowmapping.integer;
347 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer;
348 r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer;
349 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
350 r_shadow_shadowmaplod = -1;
353 if (r_shadow_fborectangle)
354 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
355 r_shadow_fborectangle = 0;
359 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
362 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
363 if (r_shadow_fbocubeside[i][0])
364 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
365 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
368 if (r_shadow_shadowmaprectangletexture)
369 R_FreeTexture(r_shadow_shadowmaprectangletexture);
370 r_shadow_shadowmaprectangletexture = NULL;
372 if (r_shadow_shadowmap2dtexture)
373 R_FreeTexture(r_shadow_shadowmap2dtexture);
374 r_shadow_shadowmap2dtexture = NULL;
376 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
377 if (r_shadow_shadowmapcubetexture[i])
378 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
379 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
381 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
382 if (r_shadow_shadowmapcubeprojectiontexture[i])
383 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]);
384 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
389 void r_shadow_start(void)
391 // allocate vertex processing arrays
393 r_shadow_attenuationgradienttexture = NULL;
394 r_shadow_attenuation2dtexture = NULL;
395 r_shadow_attenuation3dtexture = NULL;
396 r_shadow_shadowmode = 0;
397 r_shadow_shadowmaprectangletexture = NULL;
398 r_shadow_shadowmap2dtexture = NULL;
399 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
400 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
401 r_shadow_shadowmapmaxsize = 0;
402 r_shadow_shadowmapsize = 0;
403 r_shadow_shadowmaplod = 0;
404 r_shadow_shadowmapvsdct = 0;
405 r_shadow_shadowmapfilter = 0;
406 r_shadow_fborectangle = 0;
408 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
410 R_Shadow_FreeShadowMaps();
412 r_shadow_texturepool = NULL;
413 r_shadow_filters_texturepool = NULL;
414 R_Shadow_ValidateCvars();
415 R_Shadow_MakeTextures();
416 maxshadowtriangles = 0;
417 shadowelements = NULL;
418 maxshadowvertices = 0;
419 shadowvertex3f = NULL;
427 shadowmarklist = NULL;
429 r_shadow_buffer_numleafpvsbytes = 0;
430 r_shadow_buffer_visitingleafpvs = NULL;
431 r_shadow_buffer_leafpvs = NULL;
432 r_shadow_buffer_leaflist = NULL;
433 r_shadow_buffer_numsurfacepvsbytes = 0;
434 r_shadow_buffer_surfacepvs = NULL;
435 r_shadow_buffer_surfacelist = NULL;
436 r_shadow_buffer_numshadowtrispvsbytes = 0;
437 r_shadow_buffer_shadowtrispvs = NULL;
438 r_shadow_buffer_numlighttrispvsbytes = 0;
439 r_shadow_buffer_lighttrispvs = NULL;
442 void r_shadow_shutdown(void)
445 R_Shadow_UncompileWorldLights();
447 R_Shadow_FreeShadowMaps();
451 r_shadow_attenuationgradienttexture = NULL;
452 r_shadow_attenuation2dtexture = NULL;
453 r_shadow_attenuation3dtexture = NULL;
454 R_FreeTexturePool(&r_shadow_texturepool);
455 R_FreeTexturePool(&r_shadow_filters_texturepool);
456 maxshadowtriangles = 0;
458 Mem_Free(shadowelements);
459 shadowelements = NULL;
461 Mem_Free(shadowvertex3f);
462 shadowvertex3f = NULL;
465 Mem_Free(vertexupdate);
468 Mem_Free(vertexremap);
474 Mem_Free(shadowmark);
477 Mem_Free(shadowmarklist);
478 shadowmarklist = NULL;
480 r_shadow_buffer_numleafpvsbytes = 0;
481 if (r_shadow_buffer_visitingleafpvs)
482 Mem_Free(r_shadow_buffer_visitingleafpvs);
483 r_shadow_buffer_visitingleafpvs = NULL;
484 if (r_shadow_buffer_leafpvs)
485 Mem_Free(r_shadow_buffer_leafpvs);
486 r_shadow_buffer_leafpvs = NULL;
487 if (r_shadow_buffer_leaflist)
488 Mem_Free(r_shadow_buffer_leaflist);
489 r_shadow_buffer_leaflist = NULL;
490 r_shadow_buffer_numsurfacepvsbytes = 0;
491 if (r_shadow_buffer_surfacepvs)
492 Mem_Free(r_shadow_buffer_surfacepvs);
493 r_shadow_buffer_surfacepvs = NULL;
494 if (r_shadow_buffer_surfacelist)
495 Mem_Free(r_shadow_buffer_surfacelist);
496 r_shadow_buffer_surfacelist = NULL;
497 r_shadow_buffer_numshadowtrispvsbytes = 0;
498 if (r_shadow_buffer_shadowtrispvs)
499 Mem_Free(r_shadow_buffer_shadowtrispvs);
500 r_shadow_buffer_numlighttrispvsbytes = 0;
501 if (r_shadow_buffer_lighttrispvs)
502 Mem_Free(r_shadow_buffer_lighttrispvs);
505 void r_shadow_newmap(void)
507 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
508 R_Shadow_EditLights_Reload_f();
511 void R_Shadow_Help_f(void)
514 "Documentation on r_shadow system:\n"
516 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
517 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
518 "r_shadow_debuglight : render only this light number (-1 = all)\n"
519 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
520 "r_shadow_gloss2intensity : brightness of forced gloss\n"
521 "r_shadow_glossintensity : brightness of textured gloss\n"
522 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
523 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
524 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
525 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
526 "r_shadow_portallight : use portal visibility for static light precomputation\n"
527 "r_shadow_projectdistance : shadow volume projection distance\n"
528 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
529 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
530 "r_shadow_realtime_world : use high quality world lighting mode\n"
531 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
532 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
533 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
534 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
535 "r_shadow_scissor : use scissor optimization\n"
536 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
537 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
538 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
539 "r_showlighting : useful for performance testing; bright = slow!\n"
540 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
542 "r_shadow_help : this help\n"
546 void R_Shadow_Init(void)
548 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
549 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
550 Cvar_RegisterVariable(&r_shadow_usenormalmap);
551 Cvar_RegisterVariable(&r_shadow_debuglight);
552 Cvar_RegisterVariable(&r_shadow_gloss);
553 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
554 Cvar_RegisterVariable(&r_shadow_glossintensity);
555 Cvar_RegisterVariable(&r_shadow_glossexponent);
556 Cvar_RegisterVariable(&r_shadow_glossexact);
557 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
558 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
559 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
560 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
561 Cvar_RegisterVariable(&r_shadow_portallight);
562 Cvar_RegisterVariable(&r_shadow_projectdistance);
563 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
564 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
565 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
566 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
567 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
568 Cvar_RegisterVariable(&r_shadow_realtime_world);
569 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
570 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
571 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
572 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
573 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
574 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
575 Cvar_RegisterVariable(&r_shadow_scissor);
576 Cvar_RegisterVariable(&r_shadow_shadowmapping);
577 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
578 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
579 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
580 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
581 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
582 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
583 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
584 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
585 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
586 Cvar_RegisterVariable(&r_shadow_culltriangles);
587 Cvar_RegisterVariable(&r_shadow_polygonfactor);
588 Cvar_RegisterVariable(&r_shadow_polygonoffset);
589 Cvar_RegisterVariable(&r_shadow_texture3d);
590 Cvar_RegisterVariable(&r_coronas);
591 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
592 Cvar_RegisterVariable(&r_coronas_occlusionquery);
593 Cvar_RegisterVariable(&gl_flashblend);
594 Cvar_RegisterVariable(&gl_ext_separatestencil);
595 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
596 if (gamemode == GAME_TENEBRAE)
598 Cvar_SetValue("r_shadow_gloss", 2);
599 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
601 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
602 R_Shadow_EditLights_Init();
603 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
604 maxshadowtriangles = 0;
605 shadowelements = NULL;
606 maxshadowvertices = 0;
607 shadowvertex3f = NULL;
615 shadowmarklist = NULL;
617 r_shadow_buffer_numleafpvsbytes = 0;
618 r_shadow_buffer_visitingleafpvs = NULL;
619 r_shadow_buffer_leafpvs = NULL;
620 r_shadow_buffer_leaflist = NULL;
621 r_shadow_buffer_numsurfacepvsbytes = 0;
622 r_shadow_buffer_surfacepvs = NULL;
623 r_shadow_buffer_surfacelist = NULL;
624 r_shadow_buffer_shadowtrispvs = NULL;
625 r_shadow_buffer_lighttrispvs = NULL;
626 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
629 matrix4x4_t matrix_attenuationxyz =
632 {0.5, 0.0, 0.0, 0.5},
633 {0.0, 0.5, 0.0, 0.5},
634 {0.0, 0.0, 0.5, 0.5},
639 matrix4x4_t matrix_attenuationz =
642 {0.0, 0.0, 0.5, 0.5},
643 {0.0, 0.0, 0.0, 0.5},
644 {0.0, 0.0, 0.0, 0.5},
649 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
651 // make sure shadowelements is big enough for this volume
652 if (maxshadowtriangles < numtriangles)
654 maxshadowtriangles = numtriangles;
656 Mem_Free(shadowelements);
657 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
659 // make sure shadowvertex3f is big enough for this volume
660 if (maxshadowvertices < numvertices)
662 maxshadowvertices = numvertices;
664 Mem_Free(shadowvertex3f);
665 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
669 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
671 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
672 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
673 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
674 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
675 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
677 if (r_shadow_buffer_visitingleafpvs)
678 Mem_Free(r_shadow_buffer_visitingleafpvs);
679 if (r_shadow_buffer_leafpvs)
680 Mem_Free(r_shadow_buffer_leafpvs);
681 if (r_shadow_buffer_leaflist)
682 Mem_Free(r_shadow_buffer_leaflist);
683 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
684 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
685 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
686 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
688 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
690 if (r_shadow_buffer_surfacepvs)
691 Mem_Free(r_shadow_buffer_surfacepvs);
692 if (r_shadow_buffer_surfacelist)
693 Mem_Free(r_shadow_buffer_surfacelist);
694 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
695 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
696 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
698 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
700 if (r_shadow_buffer_shadowtrispvs)
701 Mem_Free(r_shadow_buffer_shadowtrispvs);
702 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
703 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
705 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
707 if (r_shadow_buffer_lighttrispvs)
708 Mem_Free(r_shadow_buffer_lighttrispvs);
709 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
710 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
714 void R_Shadow_PrepareShadowMark(int numtris)
716 // make sure shadowmark is big enough for this volume
717 if (maxshadowmark < numtris)
719 maxshadowmark = numtris;
721 Mem_Free(shadowmark);
723 Mem_Free(shadowmarklist);
724 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
725 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
729 // if shadowmarkcount wrapped we clear the array and adjust accordingly
730 if (shadowmarkcount == 0)
733 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
738 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)
741 int outtriangles = 0, outvertices = 0;
744 float ratio, direction[3], projectvector[3];
746 if (projectdirection)
747 VectorScale(projectdirection, projectdistance, projectvector);
749 VectorClear(projectvector);
751 // create the vertices
752 if (projectdirection)
754 for (i = 0;i < numshadowmarktris;i++)
756 element = inelement3i + shadowmarktris[i] * 3;
757 for (j = 0;j < 3;j++)
759 if (vertexupdate[element[j]] != vertexupdatenum)
761 vertexupdate[element[j]] = vertexupdatenum;
762 vertexremap[element[j]] = outvertices;
763 vertex = invertex3f + element[j] * 3;
764 // project one copy of the vertex according to projectvector
765 VectorCopy(vertex, outvertex3f);
766 VectorAdd(vertex, projectvector, (outvertex3f + 3));
775 for (i = 0;i < numshadowmarktris;i++)
777 element = inelement3i + shadowmarktris[i] * 3;
778 for (j = 0;j < 3;j++)
780 if (vertexupdate[element[j]] != vertexupdatenum)
782 vertexupdate[element[j]] = vertexupdatenum;
783 vertexremap[element[j]] = outvertices;
784 vertex = invertex3f + element[j] * 3;
785 // project one copy of the vertex to the sphere radius of the light
786 // (FIXME: would projecting it to the light box be better?)
787 VectorSubtract(vertex, projectorigin, direction);
788 ratio = projectdistance / VectorLength(direction);
789 VectorCopy(vertex, outvertex3f);
790 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
798 if (r_shadow_frontsidecasting.integer)
800 for (i = 0;i < numshadowmarktris;i++)
802 int remappedelement[3];
804 const int *neighbortriangle;
806 markindex = shadowmarktris[i] * 3;
807 element = inelement3i + markindex;
808 neighbortriangle = inneighbor3i + markindex;
809 // output the front and back triangles
810 outelement3i[0] = vertexremap[element[0]];
811 outelement3i[1] = vertexremap[element[1]];
812 outelement3i[2] = vertexremap[element[2]];
813 outelement3i[3] = vertexremap[element[2]] + 1;
814 outelement3i[4] = vertexremap[element[1]] + 1;
815 outelement3i[5] = vertexremap[element[0]] + 1;
819 // output the sides (facing outward from this triangle)
820 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
822 remappedelement[0] = vertexremap[element[0]];
823 remappedelement[1] = vertexremap[element[1]];
824 outelement3i[0] = remappedelement[1];
825 outelement3i[1] = remappedelement[0];
826 outelement3i[2] = remappedelement[0] + 1;
827 outelement3i[3] = remappedelement[1];
828 outelement3i[4] = remappedelement[0] + 1;
829 outelement3i[5] = remappedelement[1] + 1;
834 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
836 remappedelement[1] = vertexremap[element[1]];
837 remappedelement[2] = vertexremap[element[2]];
838 outelement3i[0] = remappedelement[2];
839 outelement3i[1] = remappedelement[1];
840 outelement3i[2] = remappedelement[1] + 1;
841 outelement3i[3] = remappedelement[2];
842 outelement3i[4] = remappedelement[1] + 1;
843 outelement3i[5] = remappedelement[2] + 1;
848 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
850 remappedelement[0] = vertexremap[element[0]];
851 remappedelement[2] = vertexremap[element[2]];
852 outelement3i[0] = remappedelement[0];
853 outelement3i[1] = remappedelement[2];
854 outelement3i[2] = remappedelement[2] + 1;
855 outelement3i[3] = remappedelement[0];
856 outelement3i[4] = remappedelement[2] + 1;
857 outelement3i[5] = remappedelement[0] + 1;
866 for (i = 0;i < numshadowmarktris;i++)
868 int remappedelement[3];
870 const int *neighbortriangle;
872 markindex = shadowmarktris[i] * 3;
873 element = inelement3i + markindex;
874 neighbortriangle = inneighbor3i + markindex;
875 // output the front and back triangles
876 outelement3i[0] = vertexremap[element[2]];
877 outelement3i[1] = vertexremap[element[1]];
878 outelement3i[2] = vertexremap[element[0]];
879 outelement3i[3] = vertexremap[element[0]] + 1;
880 outelement3i[4] = vertexremap[element[1]] + 1;
881 outelement3i[5] = vertexremap[element[2]] + 1;
885 // output the sides (facing outward from this triangle)
886 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
888 remappedelement[0] = vertexremap[element[0]];
889 remappedelement[1] = vertexremap[element[1]];
890 outelement3i[0] = remappedelement[0];
891 outelement3i[1] = remappedelement[1];
892 outelement3i[2] = remappedelement[1] + 1;
893 outelement3i[3] = remappedelement[0];
894 outelement3i[4] = remappedelement[1] + 1;
895 outelement3i[5] = remappedelement[0] + 1;
900 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
902 remappedelement[1] = vertexremap[element[1]];
903 remappedelement[2] = vertexremap[element[2]];
904 outelement3i[0] = remappedelement[1];
905 outelement3i[1] = remappedelement[2];
906 outelement3i[2] = remappedelement[2] + 1;
907 outelement3i[3] = remappedelement[1];
908 outelement3i[4] = remappedelement[2] + 1;
909 outelement3i[5] = remappedelement[1] + 1;
914 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
916 remappedelement[0] = vertexremap[element[0]];
917 remappedelement[2] = vertexremap[element[2]];
918 outelement3i[0] = remappedelement[2];
919 outelement3i[1] = remappedelement[0];
920 outelement3i[2] = remappedelement[0] + 1;
921 outelement3i[3] = remappedelement[2];
922 outelement3i[4] = remappedelement[0] + 1;
923 outelement3i[5] = remappedelement[2] + 1;
931 *outnumvertices = outvertices;
935 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)
938 int outtriangles = 0, outvertices = 0;
941 float ratio, direction[3], projectvector[3];
944 if (projectdirection)
945 VectorScale(projectdirection, projectdistance, projectvector);
947 VectorClear(projectvector);
949 for (i = 0;i < numshadowmarktris;i++)
951 int remappedelement[3];
953 const int *neighbortriangle;
955 markindex = shadowmarktris[i] * 3;
956 neighbortriangle = inneighbor3i + markindex;
957 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
958 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
959 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
960 if (side[0] + side[1] + side[2] == 0)
964 element = inelement3i + markindex;
966 // create the vertices
967 for (j = 0;j < 3;j++)
969 if (side[j] + side[j+1] == 0)
972 if (vertexupdate[k] != vertexupdatenum)
974 vertexupdate[k] = vertexupdatenum;
975 vertexremap[k] = outvertices;
976 vertex = invertex3f + k * 3;
977 VectorCopy(vertex, outvertex3f);
978 if (projectdirection)
980 // project one copy of the vertex according to projectvector
981 VectorAdd(vertex, projectvector, (outvertex3f + 3));
985 // project one copy of the vertex to the sphere radius of the light
986 // (FIXME: would projecting it to the light box be better?)
987 VectorSubtract(vertex, projectorigin, direction);
988 ratio = projectdistance / VectorLength(direction);
989 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
996 // output the sides (facing outward from this triangle)
999 remappedelement[0] = vertexremap[element[0]];
1000 remappedelement[1] = vertexremap[element[1]];
1001 outelement3i[0] = remappedelement[1];
1002 outelement3i[1] = remappedelement[0];
1003 outelement3i[2] = remappedelement[0] + 1;
1004 outelement3i[3] = remappedelement[1];
1005 outelement3i[4] = remappedelement[0] + 1;
1006 outelement3i[5] = remappedelement[1] + 1;
1013 remappedelement[1] = vertexremap[element[1]];
1014 remappedelement[2] = vertexremap[element[2]];
1015 outelement3i[0] = remappedelement[2];
1016 outelement3i[1] = remappedelement[1];
1017 outelement3i[2] = remappedelement[1] + 1;
1018 outelement3i[3] = remappedelement[2];
1019 outelement3i[4] = remappedelement[1] + 1;
1020 outelement3i[5] = remappedelement[2] + 1;
1027 remappedelement[0] = vertexremap[element[0]];
1028 remappedelement[2] = vertexremap[element[2]];
1029 outelement3i[0] = remappedelement[0];
1030 outelement3i[1] = remappedelement[2];
1031 outelement3i[2] = remappedelement[2] + 1;
1032 outelement3i[3] = remappedelement[0];
1033 outelement3i[4] = remappedelement[2] + 1;
1034 outelement3i[5] = remappedelement[0] + 1;
1041 *outnumvertices = outvertices;
1042 return outtriangles;
1045 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)
1051 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1053 tend = firsttriangle + numtris;
1054 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1056 // surface box entirely inside light box, no box cull
1057 if (projectdirection)
1059 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1061 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1062 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1063 shadowmarklist[numshadowmark++] = t;
1068 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1069 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1070 shadowmarklist[numshadowmark++] = t;
1075 // surface box not entirely inside light box, cull each triangle
1076 if (projectdirection)
1078 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1080 v[0] = invertex3f + e[0] * 3;
1081 v[1] = invertex3f + e[1] * 3;
1082 v[2] = invertex3f + e[2] * 3;
1083 TriangleNormal(v[0], v[1], v[2], normal);
1084 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1085 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1086 shadowmarklist[numshadowmark++] = t;
1091 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1093 v[0] = invertex3f + e[0] * 3;
1094 v[1] = invertex3f + e[1] * 3;
1095 v[2] = invertex3f + e[2] * 3;
1096 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1097 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1098 shadowmarklist[numshadowmark++] = t;
1104 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1109 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1111 // check if the shadow volume intersects the near plane
1113 // a ray between the eye and light origin may intersect the caster,
1114 // indicating that the shadow may touch the eye location, however we must
1115 // test the near plane (a polygon), not merely the eye location, so it is
1116 // easiest to enlarge the caster bounding shape slightly for this.
1122 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)
1124 int i, tris, outverts;
1125 if (projectdistance < 0.1)
1127 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1130 if (!numverts || !nummarktris)
1132 // make sure shadowelements is big enough for this volume
1133 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1134 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1136 if (maxvertexupdate < numverts)
1138 maxvertexupdate = numverts;
1140 Mem_Free(vertexupdate);
1142 Mem_Free(vertexremap);
1143 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1144 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1145 vertexupdatenum = 0;
1148 if (vertexupdatenum == 0)
1150 vertexupdatenum = 1;
1151 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1152 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1155 for (i = 0;i < nummarktris;i++)
1156 shadowmark[marktris[i]] = shadowmarkcount;
1158 if (r_shadow_compilingrtlight)
1160 // if we're compiling an rtlight, capture the mesh
1161 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1162 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1163 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1164 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1168 // decide which type of shadow to generate and set stencil mode
1169 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1170 // generate the sides or a solid volume, depending on type
1171 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1172 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1174 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1175 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1176 r_refdef.stats.lights_shadowtriangles += tris;
1178 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1179 GL_LockArrays(0, outverts);
1180 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1182 // increment stencil if frontface is infront of depthbuffer
1183 GL_CullFace(r_refdef.view.cullface_front);
1184 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1185 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1186 // decrement stencil if backface is infront of depthbuffer
1187 GL_CullFace(r_refdef.view.cullface_back);
1188 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1190 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1192 // decrement stencil if backface is behind depthbuffer
1193 GL_CullFace(r_refdef.view.cullface_front);
1194 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1195 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1196 // increment stencil if frontface is behind depthbuffer
1197 GL_CullFace(r_refdef.view.cullface_back);
1198 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1200 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1201 GL_LockArrays(0, 0);
1206 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)
1208 int i, tris = nummarktris;
1211 if (!numverts || !nummarktris)
1213 // make sure shadowelements is big enough for this mesh
1214 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1215 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1217 // gather up the (sparse) triangles into one array
1218 outelement3i = shadowelements;
1219 for (i = 0;i < nummarktris;i++)
1221 element = elements + marktris[i] * 3;
1222 outelement3i[0] = element[0];
1223 outelement3i[1] = element[1];
1224 outelement3i[2] = element[2];
1228 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1229 r_refdef.stats.lights_shadowtriangles += tris;
1230 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1231 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1234 static void R_Shadow_MakeTextures_MakeCorona(void)
1238 unsigned char pixels[32][32][4];
1239 for (y = 0;y < 32;y++)
1241 dy = (y - 15.5f) * (1.0f / 16.0f);
1242 for (x = 0;x < 32;x++)
1244 dx = (x - 15.5f) * (1.0f / 16.0f);
1245 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1246 a = bound(0, a, 255);
1247 pixels[y][x][0] = a;
1248 pixels[y][x][1] = a;
1249 pixels[y][x][2] = a;
1250 pixels[y][x][3] = 255;
1253 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1256 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1258 float dist = sqrt(x*x+y*y+z*z);
1259 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1260 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1261 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1264 static void R_Shadow_MakeTextures(void)
1267 float intensity, dist;
1269 R_FreeTexturePool(&r_shadow_texturepool);
1270 r_shadow_texturepool = R_AllocTexturePool();
1271 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1272 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1273 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1274 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1275 for (x = 0;x <= ATTENTABLESIZE;x++)
1277 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1278 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1279 r_shadow_attentable[x] = bound(0, intensity, 1);
1281 // 1D gradient texture
1282 for (x = 0;x < ATTEN1DSIZE;x++)
1283 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1284 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);
1285 // 2D circle texture
1286 for (y = 0;y < ATTEN2DSIZE;y++)
1287 for (x = 0;x < ATTEN2DSIZE;x++)
1288 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);
1289 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);
1290 // 3D sphere texture
1291 if (r_shadow_texture3d.integer && gl_texture3d)
1293 for (z = 0;z < ATTEN3DSIZE;z++)
1294 for (y = 0;y < ATTEN3DSIZE;y++)
1295 for (x = 0;x < ATTEN3DSIZE;x++)
1296 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));
1297 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);
1300 r_shadow_attenuation3dtexture = NULL;
1303 R_Shadow_MakeTextures_MakeCorona();
1305 // Editor light sprites
1306 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1307 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1308 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1309 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1310 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1311 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1314 void R_Shadow_ValidateCvars(void)
1316 if (r_shadow_texture3d.integer && !gl_texture3d)
1317 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1318 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1319 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1320 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1321 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1324 void R_Shadow_RenderMode_Begin(void)
1328 R_Shadow_ValidateCvars();
1330 if (!r_shadow_attenuation2dtexture
1331 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1332 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1333 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1334 R_Shadow_MakeTextures();
1337 R_Mesh_ColorPointer(NULL, 0, 0);
1338 R_Mesh_ResetTextureState();
1339 GL_BlendFunc(GL_ONE, GL_ZERO);
1340 GL_DepthRange(0, 1);
1341 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1343 GL_DepthMask(false);
1344 GL_Color(0, 0, 0, 1);
1345 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1347 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1349 if (gl_ext_separatestencil.integer)
1351 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1352 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1354 else if (gl_ext_stenciltwoside.integer)
1356 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1357 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1361 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1362 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1365 if (r_glsl.integer && gl_support_fragment_shader)
1366 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1367 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1368 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1370 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1373 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1374 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1375 r_shadow_drawbuffer = drawbuffer;
1376 r_shadow_readbuffer = readbuffer;
1379 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1381 rsurface.rtlight = rtlight;
1384 void R_Shadow_RenderMode_Reset(void)
1387 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1389 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1391 if (gl_support_ext_framebuffer_object)
1393 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1395 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1396 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1397 R_SetViewport(&r_refdef.view.viewport);
1398 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1399 R_Mesh_ColorPointer(NULL, 0, 0);
1400 R_Mesh_ResetTextureState();
1401 GL_DepthRange(0, 1);
1403 GL_DepthMask(false);
1404 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1405 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1406 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1407 qglStencilMask(~0);CHECKGLERROR
1408 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1409 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1410 GL_CullFace(r_refdef.view.cullface_back);
1411 GL_Color(1, 1, 1, 1);
1412 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1413 GL_BlendFunc(GL_ONE, GL_ZERO);
1414 R_SetupGenericShader(false);
1415 r_shadow_usingshadowmaprect = false;
1416 r_shadow_usingshadowmapcube = false;
1417 r_shadow_usingshadowmap2d = false;
1421 void R_Shadow_ClearStencil(void)
1424 GL_Clear(GL_STENCIL_BUFFER_BIT);
1425 r_refdef.stats.lights_clears++;
1428 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1430 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1431 if (r_shadow_rendermode == mode)
1434 R_Shadow_RenderMode_Reset();
1435 GL_ColorMask(0, 0, 0, 0);
1436 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1437 R_SetupDepthOrShadowShader();
1438 qglDepthFunc(GL_LESS);CHECKGLERROR
1439 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1440 r_shadow_rendermode = mode;
1445 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1446 GL_CullFace(GL_NONE);
1447 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1448 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1450 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1451 GL_CullFace(GL_NONE);
1452 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1453 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1455 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1456 GL_CullFace(GL_NONE);
1457 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1458 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1459 qglStencilMask(~0);CHECKGLERROR
1460 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1461 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1462 qglStencilMask(~0);CHECKGLERROR
1463 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1465 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1466 GL_CullFace(GL_NONE);
1467 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1468 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1469 qglStencilMask(~0);CHECKGLERROR
1470 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1471 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1472 qglStencilMask(~0);CHECKGLERROR
1473 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1478 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1483 float nearclip, farclip, bias;
1484 r_viewport_t viewport;
1486 maxsize = r_shadow_shadowmapmaxsize;
1487 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1489 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1490 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1491 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1492 if (r_shadow_shadowmode == 1)
1494 // complex unrolled cube approach (more flexible)
1495 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1496 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1497 if (!r_shadow_shadowmap2dtexture)
1500 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*4, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1501 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1502 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1503 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1507 R_Shadow_RenderMode_Reset();
1508 if (r_shadow_shadowmap2dtexture)
1510 // render depth into the fbo, do not render color at all
1511 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1512 qglDrawBuffer(GL_NONE);CHECKGLERROR
1513 qglReadBuffer(GL_NONE);CHECKGLERROR
1514 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1515 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1517 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1518 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1520 R_SetupDepthOrShadowShader();
1524 R_SetupShowDepthShader();
1525 qglClearColor(1,1,1,1);CHECKGLERROR
1527 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1528 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1529 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1530 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? size / (float)maxsize : 0.5f * (size - r_shadow_shadowmapborder);
1531 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 0.75f * size / (float)maxsize : size;
1532 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1534 else if (r_shadow_shadowmode == 2)
1536 // complex unrolled cube approach (more flexible)
1537 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1538 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1539 if (!r_shadow_shadowmaprectangletexture)
1542 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1543 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1544 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1545 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1549 R_Shadow_RenderMode_Reset();
1550 if (r_shadow_shadowmaprectangletexture)
1552 // render depth into the fbo, do not render color at all
1553 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1554 qglDrawBuffer(GL_NONE);CHECKGLERROR
1555 qglReadBuffer(GL_NONE);CHECKGLERROR
1556 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1557 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1559 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1560 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1562 R_SetupDepthOrShadowShader();
1566 R_SetupShowDepthShader();
1567 qglClearColor(1,1,1,1);CHECKGLERROR
1569 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1570 r_shadow_shadowmap_texturescale[0] = 1.0f;
1571 r_shadow_shadowmap_texturescale[1] = 1.0f;
1572 r_shadow_shadowmap_parameters[0] = r_shadow_shadowmapvsdct ? 2*size : 0.5f * (size - r_shadow_shadowmapborder);
1573 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 3*size : size;
1574 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1576 else if (r_shadow_shadowmode == 3)
1578 // simple cube approach
1579 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1582 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1583 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1584 for (i = 0;i < 6;i++)
1586 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1587 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
1592 R_Shadow_RenderMode_Reset();
1593 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1595 // render depth into the fbo, do not render color at all
1596 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1597 qglDrawBuffer(GL_NONE);CHECKGLERROR
1598 qglReadBuffer(GL_NONE);CHECKGLERROR
1599 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1600 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1602 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1603 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1605 R_SetupDepthOrShadowShader();
1609 R_SetupShowDepthShader();
1610 qglClearColor(1,1,1,1);CHECKGLERROR
1612 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1613 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1614 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1615 r_shadow_shadowmap_parameters[0] = 1.0f;
1616 r_shadow_shadowmap_parameters[1] = 1.0f;
1617 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1619 r_shadow_shadowmap_texturescale[2] = 1.0f / r_shadow_shadowmap_texturescale[0];
1620 r_shadow_shadowmap_texturescale[3] = 1.0f / r_shadow_shadowmap_texturescale[1];
1622 R_SetViewport(&viewport);
1623 GL_PolygonOffset(0, 0);
1624 GL_CullFace(GL_NONE); // quake is backwards
1625 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1628 qglClearDepth(1);CHECKGLERROR
1631 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1635 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1638 R_Shadow_RenderMode_Reset();
1639 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1642 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1646 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1647 // only draw light where this geometry was already rendered AND the
1648 // stencil is 128 (values other than this mean shadow)
1649 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1651 r_shadow_rendermode = r_shadow_lightingrendermode;
1652 // do global setup needed for the chosen lighting mode
1653 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1655 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1656 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1660 if (r_shadow_shadowmode == 1)
1662 r_shadow_usingshadowmap2d = true;
1663 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1666 else if (r_shadow_shadowmode == 2)
1668 r_shadow_usingshadowmaprect = true;
1669 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1672 else if (r_shadow_shadowmode == 3)
1674 r_shadow_usingshadowmapcube = true;
1675 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1679 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1681 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]));
1686 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1687 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1688 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1692 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1695 R_Shadow_RenderMode_Reset();
1696 GL_BlendFunc(GL_ONE, GL_ONE);
1697 GL_DepthRange(0, 1);
1698 GL_DepthTest(r_showshadowvolumes.integer < 2);
1699 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1700 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1701 GL_CullFace(GL_NONE);
1702 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1705 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1708 R_Shadow_RenderMode_Reset();
1709 GL_BlendFunc(GL_ONE, GL_ONE);
1710 GL_DepthRange(0, 1);
1711 GL_DepthTest(r_showlighting.integer < 2);
1712 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1715 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1719 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1720 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1722 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1725 void R_Shadow_RenderMode_End(void)
1728 R_Shadow_RenderMode_Reset();
1729 R_Shadow_RenderMode_ActiveLight(NULL);
1731 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1732 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1735 int bboxedges[12][2] =
1754 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1756 int i, ix1, iy1, ix2, iy2;
1757 float x1, y1, x2, y2;
1759 float vertex[20][3];
1768 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1769 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1770 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1771 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1773 if (!r_shadow_scissor.integer)
1776 // if view is inside the light box, just say yes it's visible
1777 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1780 x1 = y1 = x2 = y2 = 0;
1782 // transform all corners that are infront of the nearclip plane
1783 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1784 plane4f[3] = r_refdef.view.frustum[4].dist;
1786 for (i = 0;i < 8;i++)
1788 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1789 dist[i] = DotProduct4(corner[i], plane4f);
1790 sign[i] = dist[i] > 0;
1793 VectorCopy(corner[i], vertex[numvertices]);
1797 // if some points are behind the nearclip, add clipped edge points to make
1798 // sure that the scissor boundary is complete
1799 if (numvertices > 0 && numvertices < 8)
1801 // add clipped edge points
1802 for (i = 0;i < 12;i++)
1804 j = bboxedges[i][0];
1805 k = bboxedges[i][1];
1806 if (sign[j] != sign[k])
1808 f = dist[j] / (dist[j] - dist[k]);
1809 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1815 // if we have no points to check, the light is behind the view plane
1819 // if we have some points to transform, check what screen area is covered
1820 x1 = y1 = x2 = y2 = 0;
1822 //Con_Printf("%i vertices to transform...\n", numvertices);
1823 for (i = 0;i < numvertices;i++)
1825 VectorCopy(vertex[i], v);
1826 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1827 //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]);
1830 if (x1 > v2[0]) x1 = v2[0];
1831 if (x2 < v2[0]) x2 = v2[0];
1832 if (y1 > v2[1]) y1 = v2[1];
1833 if (y2 < v2[1]) y2 = v2[1];
1842 // now convert the scissor rectangle to integer screen coordinates
1843 ix1 = (int)(x1 - 1.0f);
1844 iy1 = vid.height - (int)(y2 - 1.0f);
1845 ix2 = (int)(x2 + 1.0f);
1846 iy2 = vid.height - (int)(y1 + 1.0f);
1847 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1849 // clamp it to the screen
1850 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1851 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1852 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1853 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1855 // if it is inside out, it's not visible
1856 if (ix2 <= ix1 || iy2 <= iy1)
1859 // the light area is visible, set up the scissor rectangle
1860 r_shadow_lightscissor[0] = ix1;
1861 r_shadow_lightscissor[1] = iy1;
1862 r_shadow_lightscissor[2] = ix2 - ix1;
1863 r_shadow_lightscissor[3] = iy2 - iy1;
1865 r_refdef.stats.lights_scissored++;
1869 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1871 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1872 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1873 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1874 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1875 if (r_textureunits.integer >= 3)
1877 if (VectorLength2(diffusecolor) > 0)
1879 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1881 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1882 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1883 if ((dot = DotProduct(n, v)) < 0)
1885 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1886 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1889 VectorCopy(ambientcolor, color4f);
1890 if (r_refdef.fogenabled)
1893 f = FogPoint_Model(vertex3f);
1894 VectorScale(color4f, f, color4f);
1901 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1903 VectorCopy(ambientcolor, color4f);
1904 if (r_refdef.fogenabled)
1907 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1908 f = FogPoint_Model(vertex3f);
1909 VectorScale(color4f, f, color4f);
1915 else if (r_textureunits.integer >= 2)
1917 if (VectorLength2(diffusecolor) > 0)
1919 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1921 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1922 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1924 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1925 if ((dot = DotProduct(n, v)) < 0)
1927 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1928 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1929 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1930 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1934 color4f[0] = ambientcolor[0] * distintensity;
1935 color4f[1] = ambientcolor[1] * distintensity;
1936 color4f[2] = ambientcolor[2] * distintensity;
1938 if (r_refdef.fogenabled)
1941 f = FogPoint_Model(vertex3f);
1942 VectorScale(color4f, f, color4f);
1946 VectorClear(color4f);
1952 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1954 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1955 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1957 color4f[0] = ambientcolor[0] * distintensity;
1958 color4f[1] = ambientcolor[1] * distintensity;
1959 color4f[2] = ambientcolor[2] * distintensity;
1960 if (r_refdef.fogenabled)
1963 f = FogPoint_Model(vertex3f);
1964 VectorScale(color4f, f, color4f);
1968 VectorClear(color4f);
1975 if (VectorLength2(diffusecolor) > 0)
1977 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1979 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1980 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1982 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1983 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1984 if ((dot = DotProduct(n, v)) < 0)
1986 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1987 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1988 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1989 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1993 color4f[0] = ambientcolor[0] * distintensity;
1994 color4f[1] = ambientcolor[1] * distintensity;
1995 color4f[2] = ambientcolor[2] * distintensity;
1997 if (r_refdef.fogenabled)
2000 f = FogPoint_Model(vertex3f);
2001 VectorScale(color4f, f, color4f);
2005 VectorClear(color4f);
2011 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2013 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2014 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2016 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2017 color4f[0] = ambientcolor[0] * distintensity;
2018 color4f[1] = ambientcolor[1] * distintensity;
2019 color4f[2] = ambientcolor[2] * distintensity;
2020 if (r_refdef.fogenabled)
2023 f = FogPoint_Model(vertex3f);
2024 VectorScale(color4f, f, color4f);
2028 VectorClear(color4f);
2035 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2037 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2040 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2041 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2042 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2043 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2044 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2046 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2048 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2049 // the cubemap normalizes this for us
2050 out3f[0] = DotProduct(svector3f, lightdir);
2051 out3f[1] = DotProduct(tvector3f, lightdir);
2052 out3f[2] = DotProduct(normal3f, lightdir);
2056 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2059 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2060 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2061 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2062 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2063 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2064 float lightdir[3], eyedir[3], halfdir[3];
2065 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2067 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2068 VectorNormalize(lightdir);
2069 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2070 VectorNormalize(eyedir);
2071 VectorAdd(lightdir, eyedir, halfdir);
2072 // the cubemap normalizes this for us
2073 out3f[0] = DotProduct(svector3f, halfdir);
2074 out3f[1] = DotProduct(tvector3f, halfdir);
2075 out3f[2] = DotProduct(normal3f, halfdir);
2079 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)
2081 // used to display how many times a surface is lit for level design purposes
2082 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2085 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)
2087 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2088 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2089 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2090 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2092 R_Mesh_ColorPointer(NULL, 0, 0);
2093 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2094 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2095 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2096 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2097 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2098 if (rsurface.texture->backgroundcurrentskinframe)
2100 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2101 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2102 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2103 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2105 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2106 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2107 if(rsurface.texture->colormapping)
2109 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2110 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2112 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2113 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2114 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2115 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2116 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2117 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2119 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2121 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2122 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2124 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2128 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)
2130 // shared final code for all the dot3 layers
2132 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2133 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2135 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2136 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2140 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)
2143 // colorscale accounts for how much we multiply the brightness
2146 // mult is how many times the final pass of the lighting will be
2147 // performed to get more brightness than otherwise possible.
2149 // Limit mult to 64 for sanity sake.
2151 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2153 // 3 3D combine path (Geforce3, Radeon 8500)
2154 memset(&m, 0, sizeof(m));
2155 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2156 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2157 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2158 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2159 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2160 m.tex[1] = R_GetTexture(basetexture);
2161 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2162 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2163 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2164 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2165 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2166 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2167 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2168 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2169 m.texmatrix[2] = rsurface.entitytolight;
2170 GL_BlendFunc(GL_ONE, GL_ONE);
2172 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2174 // 2 3D combine path (Geforce3, original Radeon)
2175 memset(&m, 0, sizeof(m));
2176 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2177 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2178 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2179 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2180 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2181 m.tex[1] = R_GetTexture(basetexture);
2182 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2183 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2184 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2185 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2186 GL_BlendFunc(GL_ONE, GL_ONE);
2188 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2190 // 4 2D combine path (Geforce3, Radeon 8500)
2191 memset(&m, 0, sizeof(m));
2192 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2193 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2194 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2195 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2196 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2197 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2198 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2199 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2200 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2201 m.texmatrix[1] = rsurface.entitytoattenuationz;
2202 m.tex[2] = R_GetTexture(basetexture);
2203 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2204 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2205 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2206 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2207 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2209 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2210 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2211 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2212 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2213 m.texmatrix[3] = rsurface.entitytolight;
2215 GL_BlendFunc(GL_ONE, GL_ONE);
2217 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2219 // 3 2D combine path (Geforce3, original Radeon)
2220 memset(&m, 0, sizeof(m));
2221 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2222 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2223 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2224 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2225 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2226 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2227 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2228 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2229 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2230 m.texmatrix[1] = rsurface.entitytoattenuationz;
2231 m.tex[2] = R_GetTexture(basetexture);
2232 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2233 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2234 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2235 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2236 GL_BlendFunc(GL_ONE, GL_ONE);
2240 // 2/2/2 2D combine path (any dot3 card)
2241 memset(&m, 0, sizeof(m));
2242 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2243 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2244 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2245 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2246 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2247 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2248 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2249 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2250 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2251 m.texmatrix[1] = rsurface.entitytoattenuationz;
2252 R_Mesh_TextureState(&m);
2253 GL_ColorMask(0,0,0,1);
2254 GL_BlendFunc(GL_ONE, GL_ZERO);
2255 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2258 memset(&m, 0, sizeof(m));
2259 m.tex[0] = R_GetTexture(basetexture);
2260 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2261 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2262 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2263 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2264 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2266 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2267 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2268 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2269 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2270 m.texmatrix[1] = rsurface.entitytolight;
2272 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2274 // this final code is shared
2275 R_Mesh_TextureState(&m);
2276 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);
2279 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)
2282 // colorscale accounts for how much we multiply the brightness
2285 // mult is how many times the final pass of the lighting will be
2286 // performed to get more brightness than otherwise possible.
2288 // Limit mult to 64 for sanity sake.
2290 // generate normalization cubemap texcoords
2291 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2292 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2294 // 3/2 3D combine path (Geforce3, Radeon 8500)
2295 memset(&m, 0, sizeof(m));
2296 m.tex[0] = R_GetTexture(normalmaptexture);
2297 m.texcombinergb[0] = GL_REPLACE;
2298 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2299 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2300 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2301 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2302 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2303 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2304 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2305 m.pointer_texcoord_bufferobject[1] = 0;
2306 m.pointer_texcoord_bufferoffset[1] = 0;
2307 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2308 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2309 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2310 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2311 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2312 R_Mesh_TextureState(&m);
2313 GL_ColorMask(0,0,0,1);
2314 GL_BlendFunc(GL_ONE, GL_ZERO);
2315 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2318 memset(&m, 0, sizeof(m));
2319 m.tex[0] = R_GetTexture(basetexture);
2320 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2321 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2322 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2323 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2324 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2326 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2327 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2328 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2329 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2330 m.texmatrix[1] = rsurface.entitytolight;
2332 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2334 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2336 // 1/2/2 3D combine path (original Radeon)
2337 memset(&m, 0, sizeof(m));
2338 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2339 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2340 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2341 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2342 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2343 R_Mesh_TextureState(&m);
2344 GL_ColorMask(0,0,0,1);
2345 GL_BlendFunc(GL_ONE, GL_ZERO);
2346 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2349 memset(&m, 0, sizeof(m));
2350 m.tex[0] = R_GetTexture(normalmaptexture);
2351 m.texcombinergb[0] = GL_REPLACE;
2352 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2353 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2354 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2355 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2356 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2357 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2358 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2359 m.pointer_texcoord_bufferobject[1] = 0;
2360 m.pointer_texcoord_bufferoffset[1] = 0;
2361 R_Mesh_TextureState(&m);
2362 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2363 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2366 memset(&m, 0, sizeof(m));
2367 m.tex[0] = R_GetTexture(basetexture);
2368 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2369 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2370 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2371 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2372 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2374 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2375 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2376 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2377 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2378 m.texmatrix[1] = rsurface.entitytolight;
2380 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2382 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2384 // 2/2 3D combine path (original Radeon)
2385 memset(&m, 0, sizeof(m));
2386 m.tex[0] = R_GetTexture(normalmaptexture);
2387 m.texcombinergb[0] = GL_REPLACE;
2388 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2389 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2390 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2391 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2392 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2393 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2394 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2395 m.pointer_texcoord_bufferobject[1] = 0;
2396 m.pointer_texcoord_bufferoffset[1] = 0;
2397 R_Mesh_TextureState(&m);
2398 GL_ColorMask(0,0,0,1);
2399 GL_BlendFunc(GL_ONE, GL_ZERO);
2400 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2403 memset(&m, 0, sizeof(m));
2404 m.tex[0] = R_GetTexture(basetexture);
2405 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2406 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2407 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2408 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2409 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2410 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2411 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2412 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2413 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2414 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2416 else if (r_textureunits.integer >= 4)
2418 // 4/2 2D combine path (Geforce3, Radeon 8500)
2419 memset(&m, 0, sizeof(m));
2420 m.tex[0] = R_GetTexture(normalmaptexture);
2421 m.texcombinergb[0] = GL_REPLACE;
2422 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2423 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2424 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2425 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2426 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2427 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2428 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2429 m.pointer_texcoord_bufferobject[1] = 0;
2430 m.pointer_texcoord_bufferoffset[1] = 0;
2431 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2432 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2433 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2434 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2435 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2436 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2437 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2438 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2439 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2440 m.texmatrix[3] = rsurface.entitytoattenuationz;
2441 R_Mesh_TextureState(&m);
2442 GL_ColorMask(0,0,0,1);
2443 GL_BlendFunc(GL_ONE, GL_ZERO);
2444 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2447 memset(&m, 0, sizeof(m));
2448 m.tex[0] = R_GetTexture(basetexture);
2449 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2450 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2451 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2452 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2453 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2455 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2456 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2457 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2458 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2459 m.texmatrix[1] = rsurface.entitytolight;
2461 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2465 // 2/2/2 2D combine path (any dot3 card)
2466 memset(&m, 0, sizeof(m));
2467 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2468 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2469 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2470 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2471 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2472 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2473 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2474 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2475 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2476 m.texmatrix[1] = rsurface.entitytoattenuationz;
2477 R_Mesh_TextureState(&m);
2478 GL_ColorMask(0,0,0,1);
2479 GL_BlendFunc(GL_ONE, GL_ZERO);
2480 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2483 memset(&m, 0, sizeof(m));
2484 m.tex[0] = R_GetTexture(normalmaptexture);
2485 m.texcombinergb[0] = GL_REPLACE;
2486 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2487 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2488 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2489 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2490 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2491 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2492 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2493 m.pointer_texcoord_bufferobject[1] = 0;
2494 m.pointer_texcoord_bufferoffset[1] = 0;
2495 R_Mesh_TextureState(&m);
2496 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2497 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2500 memset(&m, 0, sizeof(m));
2501 m.tex[0] = R_GetTexture(basetexture);
2502 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2503 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2504 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2505 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2506 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2508 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2509 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2510 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2511 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2512 m.texmatrix[1] = rsurface.entitytolight;
2514 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2516 // this final code is shared
2517 R_Mesh_TextureState(&m);
2518 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);
2521 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)
2523 float glossexponent;
2525 // FIXME: detect blendsquare!
2526 //if (!gl_support_blendsquare)
2529 // generate normalization cubemap texcoords
2530 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2531 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2533 // 2/0/0/1/2 3D combine blendsquare path
2534 memset(&m, 0, sizeof(m));
2535 m.tex[0] = R_GetTexture(normalmaptexture);
2536 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2537 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2538 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2539 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2540 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2541 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2542 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2543 m.pointer_texcoord_bufferobject[1] = 0;
2544 m.pointer_texcoord_bufferoffset[1] = 0;
2545 R_Mesh_TextureState(&m);
2546 GL_ColorMask(0,0,0,1);
2547 // this squares the result
2548 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2549 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2551 // second and third pass
2552 R_Mesh_ResetTextureState();
2553 // square alpha in framebuffer a few times to make it shiny
2554 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2555 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2556 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2559 memset(&m, 0, sizeof(m));
2560 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2561 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2562 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2563 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2564 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2565 R_Mesh_TextureState(&m);
2566 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2567 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2570 memset(&m, 0, sizeof(m));
2571 m.tex[0] = R_GetTexture(glosstexture);
2572 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2573 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2574 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2575 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2576 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2578 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2579 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2580 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2581 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2582 m.texmatrix[1] = rsurface.entitytolight;
2584 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2586 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2588 // 2/0/0/2 3D combine blendsquare path
2589 memset(&m, 0, sizeof(m));
2590 m.tex[0] = R_GetTexture(normalmaptexture);
2591 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2592 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2593 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2594 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2595 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2596 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2597 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2598 m.pointer_texcoord_bufferobject[1] = 0;
2599 m.pointer_texcoord_bufferoffset[1] = 0;
2600 R_Mesh_TextureState(&m);
2601 GL_ColorMask(0,0,0,1);
2602 // this squares the result
2603 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2604 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2606 // second and third pass
2607 R_Mesh_ResetTextureState();
2608 // square alpha in framebuffer a few times to make it shiny
2609 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2610 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2611 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2614 memset(&m, 0, sizeof(m));
2615 m.tex[0] = R_GetTexture(glosstexture);
2616 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2617 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2618 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2619 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2620 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2621 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2622 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2623 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2624 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2625 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2629 // 2/0/0/2/2 2D combine blendsquare path
2630 memset(&m, 0, sizeof(m));
2631 m.tex[0] = R_GetTexture(normalmaptexture);
2632 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2633 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2634 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2635 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2636 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2637 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2638 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2639 m.pointer_texcoord_bufferobject[1] = 0;
2640 m.pointer_texcoord_bufferoffset[1] = 0;
2641 R_Mesh_TextureState(&m);
2642 GL_ColorMask(0,0,0,1);
2643 // this squares the result
2644 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2645 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2647 // second and third pass
2648 R_Mesh_ResetTextureState();
2649 // square alpha in framebuffer a few times to make it shiny
2650 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2651 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2652 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2655 memset(&m, 0, sizeof(m));
2656 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2657 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2658 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2659 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2660 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2661 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2662 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2663 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2664 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2665 m.texmatrix[1] = rsurface.entitytoattenuationz;
2666 R_Mesh_TextureState(&m);
2667 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2668 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2671 memset(&m, 0, sizeof(m));
2672 m.tex[0] = R_GetTexture(glosstexture);
2673 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2674 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2675 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2676 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2677 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2679 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2680 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2681 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2682 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2683 m.texmatrix[1] = rsurface.entitytolight;
2685 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2687 // this final code is shared
2688 R_Mesh_TextureState(&m);
2689 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);
2692 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)
2694 // ARB path (any Geforce, any Radeon)
2695 qboolean doambient = ambientscale > 0;
2696 qboolean dodiffuse = diffusescale > 0;
2697 qboolean dospecular = specularscale > 0;
2698 if (!doambient && !dodiffuse && !dospecular)
2700 R_Mesh_ColorPointer(NULL, 0, 0);
2702 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2704 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2708 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2710 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2715 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2717 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2720 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2723 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2730 int newnumtriangles;
2734 int maxtriangles = 4096;
2735 int newelements[4096*3];
2736 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2737 for (renders = 0;renders < 64;renders++)
2742 newnumtriangles = 0;
2744 // due to low fillrate on the cards this vertex lighting path is
2745 // designed for, we manually cull all triangles that do not
2746 // contain a lit vertex
2747 // this builds batches of triangles from multiple surfaces and
2748 // renders them at once
2749 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2751 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2753 if (newnumtriangles)
2755 newfirstvertex = min(newfirstvertex, e[0]);
2756 newlastvertex = max(newlastvertex, e[0]);
2760 newfirstvertex = e[0];
2761 newlastvertex = e[0];
2763 newfirstvertex = min(newfirstvertex, e[1]);
2764 newlastvertex = max(newlastvertex, e[1]);
2765 newfirstvertex = min(newfirstvertex, e[2]);
2766 newlastvertex = max(newlastvertex, e[2]);
2772 if (newnumtriangles >= maxtriangles)
2774 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2775 newnumtriangles = 0;
2781 if (newnumtriangles >= 1)
2783 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2786 // if we couldn't find any lit triangles, exit early
2789 // now reduce the intensity for the next overbright pass
2790 // we have to clamp to 0 here incase the drivers have improper
2791 // handling of negative colors
2792 // (some old drivers even have improper handling of >1 color)
2794 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2796 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2798 c[0] = max(0, c[0] - 1);
2799 c[1] = max(0, c[1] - 1);
2800 c[2] = max(0, c[2] - 1);
2812 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)
2814 // OpenGL 1.1 path (anything)
2815 float ambientcolorbase[3], diffusecolorbase[3];
2816 float ambientcolorpants[3], diffusecolorpants[3];
2817 float ambientcolorshirt[3], diffusecolorshirt[3];
2819 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2820 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2821 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2822 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2823 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2824 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2825 memset(&m, 0, sizeof(m));
2826 m.tex[0] = R_GetTexture(basetexture);
2827 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2828 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2829 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2830 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2831 if (r_textureunits.integer >= 2)
2834 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2835 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2836 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2837 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2838 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2839 if (r_textureunits.integer >= 3)
2841 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2842 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2843 m.texmatrix[2] = rsurface.entitytoattenuationz;
2844 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2845 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2846 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2849 R_Mesh_TextureState(&m);
2850 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2851 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2854 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2855 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2859 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2860 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2864 extern cvar_t gl_lightmaps;
2865 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)
2867 float ambientscale, diffusescale, specularscale;
2868 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2870 // calculate colors to render this texture with
2871 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2872 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2873 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2874 ambientscale = rsurface.rtlight->ambientscale;
2875 diffusescale = rsurface.rtlight->diffusescale;
2876 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2877 if (!r_shadow_usenormalmap.integer)
2879 ambientscale += 1.0f * diffusescale;
2883 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2885 RSurf_SetupDepthAndCulling();
2886 nmap = rsurface.texture->currentskinframe->nmap;
2887 if (gl_lightmaps.integer)
2888 nmap = r_texture_blanknormalmap;
2889 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2891 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2892 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2895 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2896 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2897 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2900 VectorClear(lightcolorpants);
2903 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2904 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2905 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2908 VectorClear(lightcolorshirt);
2909 switch (r_shadow_rendermode)
2911 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2912 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2913 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);
2915 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2916 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);
2918 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2919 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);
2921 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2922 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);
2925 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2931 switch (r_shadow_rendermode)
2933 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2934 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2935 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);
2937 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2938 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);
2940 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2941 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);
2943 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2944 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);
2947 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2953 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)
2955 matrix4x4_t tempmatrix = *matrix;
2956 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2958 // if this light has been compiled before, free the associated data
2959 R_RTLight_Uncompile(rtlight);
2961 // clear it completely to avoid any lingering data
2962 memset(rtlight, 0, sizeof(*rtlight));
2964 // copy the properties
2965 rtlight->matrix_lighttoworld = tempmatrix;
2966 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2967 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2968 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2969 VectorCopy(color, rtlight->color);
2970 rtlight->cubemapname[0] = 0;
2971 if (cubemapname && cubemapname[0])
2972 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2973 rtlight->shadow = shadow;
2974 rtlight->corona = corona;
2975 rtlight->style = style;
2976 rtlight->isstatic = isstatic;
2977 rtlight->coronasizescale = coronasizescale;
2978 rtlight->ambientscale = ambientscale;
2979 rtlight->diffusescale = diffusescale;
2980 rtlight->specularscale = specularscale;
2981 rtlight->flags = flags;
2983 // compute derived data
2984 //rtlight->cullradius = rtlight->radius;
2985 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2986 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2987 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2988 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2989 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2990 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2991 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2994 // compiles rtlight geometry
2995 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2996 void R_RTLight_Compile(rtlight_t *rtlight)
2999 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3000 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3001 entity_render_t *ent = r_refdef.scene.worldentity;
3002 dp_model_t *model = r_refdef.scene.worldmodel;
3003 unsigned char *data;
3006 // compile the light
3007 rtlight->compiled = true;
3008 rtlight->static_numleafs = 0;
3009 rtlight->static_numleafpvsbytes = 0;
3010 rtlight->static_leaflist = NULL;
3011 rtlight->static_leafpvs = NULL;
3012 rtlight->static_numsurfaces = 0;
3013 rtlight->static_surfacelist = NULL;
3014 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3015 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3016 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3017 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3018 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3019 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3021 if (model && model->GetLightInfo)
3023 // this variable must be set for the CompileShadowVolume code
3024 r_shadow_compilingrtlight = rtlight;
3025 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);
3026 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);
3027 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3028 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3029 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3030 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3031 rtlight->static_numsurfaces = numsurfaces;
3032 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3033 rtlight->static_numleafs = numleafs;
3034 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3035 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3036 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3037 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3038 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3039 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3040 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3041 if (rtlight->static_numsurfaces)
3042 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3043 if (rtlight->static_numleafs)
3044 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3045 if (rtlight->static_numleafpvsbytes)
3046 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3047 if (rtlight->static_numshadowtrispvsbytes)
3048 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3049 if (rtlight->static_numlighttrispvsbytes)
3050 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3051 if (model->CompileShadowVolume && rtlight->shadow)
3052 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3053 // now we're done compiling the rtlight
3054 r_shadow_compilingrtlight = NULL;
3058 // use smallest available cullradius - box radius or light radius
3059 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3060 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3062 shadowzpasstris = 0;
3063 if (rtlight->static_meshchain_shadow_zpass)
3064 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3065 shadowzpasstris += mesh->numtriangles;
3067 shadowzfailtris = 0;
3068 if (rtlight->static_meshchain_shadow_zfail)
3069 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3070 shadowzfailtris += mesh->numtriangles;
3073 if (rtlight->static_numlighttrispvsbytes)
3074 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3075 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3079 if (rtlight->static_numlighttrispvsbytes)
3080 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3081 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3084 if (developer.integer >= 10)
3085 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);
3088 void R_RTLight_Uncompile(rtlight_t *rtlight)
3090 if (rtlight->compiled)
3092 if (rtlight->static_meshchain_shadow_zpass)
3093 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3094 rtlight->static_meshchain_shadow_zpass = NULL;
3095 if (rtlight->static_meshchain_shadow_zfail)
3096 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3097 rtlight->static_meshchain_shadow_zfail = NULL;
3098 // these allocations are grouped
3099 if (rtlight->static_surfacelist)
3100 Mem_Free(rtlight->static_surfacelist);
3101 rtlight->static_numleafs = 0;
3102 rtlight->static_numleafpvsbytes = 0;
3103 rtlight->static_leaflist = NULL;
3104 rtlight->static_leafpvs = NULL;
3105 rtlight->static_numsurfaces = 0;
3106 rtlight->static_surfacelist = NULL;
3107 rtlight->static_numshadowtrispvsbytes = 0;
3108 rtlight->static_shadowtrispvs = NULL;
3109 rtlight->static_numlighttrispvsbytes = 0;
3110 rtlight->static_lighttrispvs = NULL;
3111 rtlight->compiled = false;
3115 void R_Shadow_UncompileWorldLights(void)
3119 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3120 for (lightindex = 0;lightindex < range;lightindex++)
3122 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3125 R_RTLight_Uncompile(&light->rtlight);
3129 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3133 // reset the count of frustum planes
3134 // see rsurface.rtlight_frustumplanes definition for how much this array
3136 rsurface.rtlight_numfrustumplanes = 0;
3138 // haven't implemented a culling path for ortho rendering
3139 if (!r_refdef.view.useperspective)
3141 // check if the light is on screen and copy the 4 planes if it is
3142 for (i = 0;i < 4;i++)
3143 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3146 for (i = 0;i < 4;i++)
3147 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3152 // generate a deformed frustum that includes the light origin, this is
3153 // used to cull shadow casting surfaces that can not possibly cast a
3154 // shadow onto the visible light-receiving surfaces, which can be a
3157 // if the light origin is onscreen the result will be 4 planes exactly
3158 // if the light origin is offscreen on only one axis the result will
3159 // be exactly 5 planes (split-side case)
3160 // if the light origin is offscreen on two axes the result will be
3161 // exactly 4 planes (stretched corner case)
3162 for (i = 0;i < 4;i++)
3164 // quickly reject standard frustum planes that put the light
3165 // origin outside the frustum
3166 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3169 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3171 // if all the standard frustum planes were accepted, the light is onscreen
3172 // otherwise we need to generate some more planes below...
3173 if (rsurface.rtlight_numfrustumplanes < 4)
3175 // at least one of the stock frustum planes failed, so we need to
3176 // create one or two custom planes to enclose the light origin
3177 for (i = 0;i < 4;i++)
3179 // create a plane using the view origin and light origin, and a
3180 // single point from the frustum corner set
3181 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3182 VectorNormalize(plane.normal);
3183 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3184 // see if this plane is backwards and flip it if so
3185 for (j = 0;j < 4;j++)
3186 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3190 VectorNegate(plane.normal, plane.normal);
3192 // flipped plane, test again to see if it is now valid
3193 for (j = 0;j < 4;j++)
3194 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3196 // if the plane is still not valid, then it is dividing the
3197 // frustum and has to be rejected
3201 // we have created a valid plane, compute extra info
3202 PlaneClassify(&plane);
3204 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3206 // if we've found 5 frustum planes then we have constructed a
3207 // proper split-side case and do not need to keep searching for
3208 // planes to enclose the light origin
3209 if (rsurface.rtlight_numfrustumplanes == 5)
3217 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3219 plane = rsurface.rtlight_frustumplanes[i];
3220 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));
3225 // now add the light-space box planes if the light box is rotated, as any
3226 // caster outside the oriented light box is irrelevant (even if it passed
3227 // the worldspace light box, which is axial)
3228 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3230 for (i = 0;i < 6;i++)
3234 v[i >> 1] = (i & 1) ? -1 : 1;
3235 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3236 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3237 plane.dist = VectorNormalizeLength(plane.normal);
3238 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3239 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3245 // add the world-space reduced box planes
3246 for (i = 0;i < 6;i++)
3248 VectorClear(plane.normal);
3249 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3250 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3251 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3260 // reduce all plane distances to tightly fit the rtlight cull box, which
3262 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3263 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3264 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3265 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3266 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3267 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3268 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3269 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3270 oldnum = rsurface.rtlight_numfrustumplanes;
3271 rsurface.rtlight_numfrustumplanes = 0;
3272 for (j = 0;j < oldnum;j++)
3274 // find the nearest point on the box to this plane
3275 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3276 for (i = 1;i < 8;i++)
3278 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3279 if (bestdist > dist)
3282 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);
3283 // if the nearest point is near or behind the plane, we want this
3284 // plane, otherwise the plane is useless as it won't cull anything
3285 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3287 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3288 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3295 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3300 int surfacelistindex;
3301 msurface_t *surface;
3303 RSurf_ActiveWorldEntity();
3304 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3306 if (r_refdef.scene.worldentity->model)
3307 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3308 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3312 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3315 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3316 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3317 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3318 for (;mesh;mesh = mesh->next)
3320 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3321 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3322 GL_LockArrays(0, mesh->numverts);
3323 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3325 // increment stencil if frontface is infront of depthbuffer
3326 GL_CullFace(r_refdef.view.cullface_back);
3327 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3328 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3329 // decrement stencil if backface is infront of depthbuffer
3330 GL_CullFace(r_refdef.view.cullface_front);
3331 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3333 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3335 // decrement stencil if backface is behind depthbuffer
3336 GL_CullFace(r_refdef.view.cullface_front);
3337 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3338 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3339 // increment stencil if frontface is behind depthbuffer
3340 GL_CullFace(r_refdef.view.cullface_back);
3341 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3343 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3344 GL_LockArrays(0, 0);
3348 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3350 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3351 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3353 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3354 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3355 if (CHECKPVSBIT(trispvs, t))
3356 shadowmarklist[numshadowmark++] = t;
3358 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);
3360 else if (numsurfaces)
3361 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3363 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3366 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3368 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3369 vec_t relativeshadowradius;
3370 RSurf_ActiveModelEntity(ent, false, false);
3371 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3372 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3373 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3374 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3375 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3376 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3377 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3378 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3379 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3380 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3382 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3383 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3386 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3388 // set up properties for rendering light onto this entity
3389 RSurf_ActiveModelEntity(ent, true, true);
3390 GL_AlphaTest(false);
3391 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3392 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3393 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3394 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3395 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3396 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3399 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3401 if (!r_refdef.scene.worldmodel->DrawLight)
3404 // set up properties for rendering light onto this entity
3405 RSurf_ActiveWorldEntity();
3406 GL_AlphaTest(false);
3407 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3408 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3409 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3410 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3411 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3412 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3414 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3416 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3419 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3421 dp_model_t *model = ent->model;
3422 if (!model->DrawLight)
3425 R_Shadow_SetupEntityLight(ent);
3427 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3429 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3433 {{ 0, 0, 0}, "px", true, true, true},
3434 {{ 0, 90, 0}, "py", false, true, false},
3435 {{ 0, 180, 0}, "nx", false, false, true},
3436 {{ 0, 270, 0}, "ny", true, false, false},
3437 {{-90, 180, 0}, "pz", false, false, true},
3438 {{ 90, 180, 0}, "nz", false, false, true}
3441 static const double shadowviewmat16[6][4][4] =
3481 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3485 int numleafs, numsurfaces;
3486 int *leaflist, *surfacelist;
3487 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3488 int numlightentities;
3489 int numlightentities_noselfshadow;
3490 int numshadowentities;
3491 int numshadowentities_noselfshadow;
3492 static entity_render_t *lightentities[MAX_EDICTS];
3493 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3494 static entity_render_t *shadowentities[MAX_EDICTS];
3495 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3496 vec3_t nearestpoint;
3498 qboolean castshadows;
3501 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3502 // skip lights that are basically invisible (color 0 0 0)
3503 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3506 // loading is done before visibility checks because loading should happen
3507 // all at once at the start of a level, not when it stalls gameplay.
3508 // (especially important to benchmarks)
3510 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3511 R_RTLight_Compile(rtlight);
3513 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3515 // look up the light style value at this time
3516 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3517 VectorScale(rtlight->color, f, rtlight->currentcolor);
3519 if (rtlight->selected)
3521 f = 2 + sin(realtime * M_PI * 4.0);
3522 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3526 // if lightstyle is currently off, don't draw the light
3527 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3530 // if the light box is offscreen, skip it
3531 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3534 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3535 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3537 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3539 // compiled light, world available and can receive realtime lighting
3540 // retrieve leaf information
3541 numleafs = rtlight->static_numleafs;
3542 leaflist = rtlight->static_leaflist;
3543 leafpvs = rtlight->static_leafpvs;
3544 numsurfaces = rtlight->static_numsurfaces;
3545 surfacelist = rtlight->static_surfacelist;
3546 shadowtrispvs = rtlight->static_shadowtrispvs;
3547 lighttrispvs = rtlight->static_lighttrispvs;
3549 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3551 // dynamic light, world available and can receive realtime lighting
3552 // calculate lit surfaces and leafs
3553 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);
3554 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);
3555 leaflist = r_shadow_buffer_leaflist;
3556 leafpvs = r_shadow_buffer_leafpvs;
3557 surfacelist = r_shadow_buffer_surfacelist;
3558 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3559 lighttrispvs = r_shadow_buffer_lighttrispvs;
3560 // if the reduced leaf bounds are offscreen, skip it
3561 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3572 shadowtrispvs = NULL;
3573 lighttrispvs = NULL;
3575 // check if light is illuminating any visible leafs
3578 for (i = 0;i < numleafs;i++)
3579 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3584 // set up a scissor rectangle for this light
3585 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3588 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3590 // make a list of lit entities and shadow casting entities
3591 numlightentities = 0;
3592 numlightentities_noselfshadow = 0;
3593 numshadowentities = 0;
3594 numshadowentities_noselfshadow = 0;
3595 // add dynamic entities that are lit by the light
3596 if (r_drawentities.integer)
3598 for (i = 0;i < r_refdef.scene.numentities;i++)
3601 entity_render_t *ent = r_refdef.scene.entities[i];
3603 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3605 // skip the object entirely if it is not within the valid
3606 // shadow-casting region (which includes the lit region)
3607 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3609 if (!(model = ent->model))
3611 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3613 // this entity wants to receive light, is visible, and is
3614 // inside the light box
3615 // TODO: check if the surfaces in the model can receive light
3616 // so now check if it's in a leaf seen by the light
3617 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))
3619 if (ent->flags & RENDER_NOSELFSHADOW)
3620 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3622 lightentities[numlightentities++] = ent;
3623 // since it is lit, it probably also casts a shadow...
3624 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3625 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3626 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3628 // note: exterior models without the RENDER_NOSELFSHADOW
3629 // flag still create a RENDER_NOSELFSHADOW shadow but
3630 // are lit normally, this means that they are
3631 // self-shadowing but do not shadow other
3632 // RENDER_NOSELFSHADOW entities such as the gun
3633 // (very weird, but keeps the player shadow off the gun)
3634 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3635 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3637 shadowentities[numshadowentities++] = ent;
3640 else if (ent->flags & RENDER_SHADOW)
3642 // this entity is not receiving light, but may still need to
3644 // TODO: check if the surfaces in the model can cast shadow
3645 // now check if it is in a leaf seen by the light
3646 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))
3648 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3649 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3650 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3652 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3653 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3655 shadowentities[numshadowentities++] = ent;
3661 // return if there's nothing at all to light
3662 if (!numlightentities && !numsurfaces)
3665 // don't let sound skip if going slow
3666 if (r_refdef.scene.extraupdate)
3669 // make this the active rtlight for rendering purposes
3670 R_Shadow_RenderMode_ActiveLight(rtlight);
3671 // count this light in the r_speeds
3672 r_refdef.stats.lights++;
3674 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3676 // optionally draw visible shape of the shadow volumes
3677 // for performance analysis by level designers
3678 R_Shadow_RenderMode_VisibleShadowVolumes();
3680 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3681 for (i = 0;i < numshadowentities;i++)
3682 R_Shadow_DrawEntityShadow(shadowentities[i]);
3683 for (i = 0;i < numshadowentities_noselfshadow;i++)
3684 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3687 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3689 // optionally draw the illuminated areas
3690 // for performance analysis by level designers
3691 R_Shadow_RenderMode_VisibleLighting(false, false);
3693 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3694 for (i = 0;i < numlightentities;i++)
3695 R_Shadow_DrawEntityLight(lightentities[i]);
3696 for (i = 0;i < numlightentities_noselfshadow;i++)
3697 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3700 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3702 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3703 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3704 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3705 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3706 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3707 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3709 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3714 r_shadow_shadowmaplod = 0;
3715 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3716 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3717 r_shadow_shadowmaplod = i;
3719 size = r_shadow_shadowmapvsdct || r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3720 size = bound(1, size, 2048);
3722 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3724 // render shadow casters into 6 sided depth texture
3725 for (side = 0;side < 6;side++)
3727 R_Shadow_RenderMode_ShadowMap(side, true, size);
3729 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3730 for (i = 0;i < numshadowentities;i++)
3731 R_Shadow_DrawEntityShadow(shadowentities[i]);
3734 if (numlightentities_noselfshadow)
3736 // render lighting using the depth texture as shadowmap
3737 // draw lighting in the unmasked areas
3738 R_Shadow_RenderMode_Lighting(false, false, true);
3739 for (i = 0;i < numlightentities_noselfshadow;i++)
3740 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3743 // render shadow casters into 6 sided depth texture
3744 for (side = 0;side < 6;side++)
3746 R_Shadow_RenderMode_ShadowMap(side, false, size);
3747 for (i = 0;i < numshadowentities_noselfshadow;i++)
3748 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3751 // render lighting using the depth texture as shadowmap
3752 // draw lighting in the unmasked areas
3753 R_Shadow_RenderMode_Lighting(false, false, true);
3754 // draw lighting in the unmasked areas
3756 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3757 for (i = 0;i < numlightentities;i++)
3758 R_Shadow_DrawEntityLight(lightentities[i]);
3760 else if (castshadows && gl_stencil)
3762 // draw stencil shadow volumes to mask off pixels that are in shadow
3763 // so that they won't receive lighting
3764 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3765 R_Shadow_ClearStencil();
3767 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3768 for (i = 0;i < numshadowentities;i++)
3769 R_Shadow_DrawEntityShadow(shadowentities[i]);
3770 if (numlightentities_noselfshadow)
3772 // draw lighting in the unmasked areas
3773 R_Shadow_RenderMode_Lighting(true, false, false);
3774 for (i = 0;i < numlightentities_noselfshadow;i++)
3775 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3777 // optionally draw the illuminated areas
3778 // for performance analysis by level designers
3779 if (r_showlighting.integer && r_refdef.view.showdebug)
3781 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3782 for (i = 0;i < numlightentities_noselfshadow;i++)
3783 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3786 for (i = 0;i < numshadowentities_noselfshadow;i++)
3787 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3789 if (numsurfaces + numlightentities)
3791 // draw lighting in the unmasked areas
3792 R_Shadow_RenderMode_Lighting(true, false, false);
3794 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3795 for (i = 0;i < numlightentities;i++)
3796 R_Shadow_DrawEntityLight(lightentities[i]);
3801 if (numsurfaces + numlightentities)
3803 // draw lighting in the unmasked areas
3804 R_Shadow_RenderMode_Lighting(false, false, false);
3806 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3807 for (i = 0;i < numlightentities;i++)
3808 R_Shadow_DrawEntityLight(lightentities[i]);
3809 for (i = 0;i < numlightentities_noselfshadow;i++)
3810 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3815 void R_Shadow_DrawLightSprites(void);
3816 void R_ShadowVolumeLighting(qboolean visible)
3824 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapvsdct != r_shadow_shadowmapping_vsdct.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3825 R_Shadow_FreeShadowMaps();
3827 if (r_editlights.integer)
3828 R_Shadow_DrawLightSprites();
3830 R_Shadow_RenderMode_Begin();
3832 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3833 if (r_shadow_debuglight.integer >= 0)
3835 lightindex = r_shadow_debuglight.integer;
3836 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3837 if (light && (light->flags & flag))
3838 R_DrawRTLight(&light->rtlight, visible);
3842 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3843 for (lightindex = 0;lightindex < range;lightindex++)
3845 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3846 if (light && (light->flags & flag))
3847 R_DrawRTLight(&light->rtlight, visible);
3850 if (r_refdef.scene.rtdlight)
3851 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3852 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3854 R_Shadow_RenderMode_End();
3857 extern const float r_screenvertex3f[12];
3858 extern void R_SetupView(qboolean allowwaterclippingplane);
3859 extern void R_ResetViewRendering3D(void);
3860 extern void R_ResetViewRendering2D(void);
3861 extern cvar_t r_shadows;
3862 extern cvar_t r_shadows_darken;
3863 extern cvar_t r_shadows_drawafterrtlighting;
3864 extern cvar_t r_shadows_castfrombmodels;
3865 extern cvar_t r_shadows_throwdistance;
3866 extern cvar_t r_shadows_throwdirection;
3867 void R_DrawModelShadows(void)
3870 float relativethrowdistance;
3871 entity_render_t *ent;
3872 vec3_t relativelightorigin;
3873 vec3_t relativelightdirection;
3874 vec3_t relativeshadowmins, relativeshadowmaxs;
3875 vec3_t tmp, shadowdir;
3877 if (!r_drawentities.integer || !gl_stencil)
3881 R_ResetViewRendering3D();
3882 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3883 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3884 R_Shadow_RenderMode_Begin();
3885 R_Shadow_RenderMode_ActiveLight(NULL);
3886 r_shadow_lightscissor[0] = r_refdef.view.x;
3887 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3888 r_shadow_lightscissor[2] = r_refdef.view.width;
3889 r_shadow_lightscissor[3] = r_refdef.view.height;
3890 R_Shadow_RenderMode_StencilShadowVolumes(false);
3893 if (r_shadows.integer == 2)
3895 Math_atov(r_shadows_throwdirection.string, shadowdir);
3896 VectorNormalize(shadowdir);
3899 R_Shadow_ClearStencil();
3901 for (i = 0;i < r_refdef.scene.numentities;i++)
3903 ent = r_refdef.scene.entities[i];
3905 // cast shadows from anything of the map (submodels are optional)
3906 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3908 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3909 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3910 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3911 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3912 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3915 if(ent->entitynumber != 0)
3917 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3918 int entnum, entnum2, recursion;
3919 entnum = entnum2 = ent->entitynumber;
3920 for(recursion = 32; recursion > 0; --recursion)
3922 entnum2 = cl.entities[entnum].state_current.tagentity;
3923 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3928 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3930 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3931 // transform into modelspace of OUR entity
3932 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3933 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3936 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3939 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3942 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3943 RSurf_ActiveModelEntity(ent, false, false);
3944 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3945 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3949 // not really the right mode, but this will disable any silly stencil features
3950 R_Shadow_RenderMode_End();
3952 // set up ortho view for rendering this pass
3953 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3954 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3955 //GL_ScissorTest(true);
3956 //R_Mesh_Matrix(&identitymatrix);
3957 //R_Mesh_ResetTextureState();
3958 R_ResetViewRendering2D();
3959 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3960 R_Mesh_ColorPointer(NULL, 0, 0);
3961 R_SetupGenericShader(false);
3963 // set up a darkening blend on shadowed areas
3964 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3965 //GL_DepthRange(0, 1);
3966 //GL_DepthTest(false);
3967 //GL_DepthMask(false);
3968 //GL_PolygonOffset(0, 0);CHECKGLERROR
3969 GL_Color(0, 0, 0, r_shadows_darken.value);
3970 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3971 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3972 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3973 qglStencilMask(~0);CHECKGLERROR
3974 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3975 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3977 // apply the blend to the shadowed areas
3978 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3980 // restore the viewport
3981 R_SetViewport(&r_refdef.view.viewport);
3983 // restore other state to normal
3984 //R_Shadow_RenderMode_End();
3987 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3990 vec3_t centerorigin;
3991 // if it's too close, skip it
3992 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3994 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3997 if (usequery && r_numqueries + 2 <= r_maxqueries)
3999 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4000 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4001 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4004 // 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
4005 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4006 qglDepthFunc(GL_ALWAYS);
4007 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);
4008 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4009 qglDepthFunc(GL_LEQUAL);
4010 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4011 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);
4012 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4015 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4018 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4021 GLint allpixels = 0, visiblepixels = 0;
4022 // now we have to check the query result
4023 if (rtlight->corona_queryindex_visiblepixels)
4026 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4027 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4029 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4030 if (visiblepixels < 1 || allpixels < 1)
4032 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4033 cscale *= rtlight->corona_visibility;
4037 // FIXME: these traces should scan all render entities instead of cl.world
4038 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4041 VectorScale(rtlight->color, cscale, color);
4042 if (VectorLength(color) > (1.0f / 256.0f))
4043 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);
4046 void R_DrawCoronas(void)
4054 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4056 if (r_waterstate.renderingscene)
4058 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4059 R_Mesh_Matrix(&identitymatrix);
4061 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4063 // check occlusion of coronas
4064 // use GL_ARB_occlusion_query if available
4065 // otherwise use raytraces
4067 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4070 GL_ColorMask(0,0,0,0);
4071 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4072 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4075 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4076 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4078 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4082 for (lightindex = 0;lightindex < range;lightindex++)
4084 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4087 rtlight = &light->rtlight;
4088 rtlight->corona_visibility = 0;
4089 rtlight->corona_queryindex_visiblepixels = 0;
4090 rtlight->corona_queryindex_allpixels = 0;
4091 if (!(rtlight->flags & flag))
4093 if (rtlight->corona <= 0)
4095 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4097 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4099 for (i = 0;i < r_refdef.scene.numlights;i++)
4101 rtlight = r_refdef.scene.lights[i];
4102 rtlight->corona_visibility = 0;
4103 rtlight->corona_queryindex_visiblepixels = 0;
4104 rtlight->corona_queryindex_allpixels = 0;
4105 if (!(rtlight->flags & flag))
4107 if (rtlight->corona <= 0)
4109 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4112 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4114 // now draw the coronas using the query data for intensity info
4115 for (lightindex = 0;lightindex < range;lightindex++)
4117 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4120 rtlight = &light->rtlight;
4121 if (rtlight->corona_visibility <= 0)
4123 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4125 for (i = 0;i < r_refdef.scene.numlights;i++)
4127 rtlight = r_refdef.scene.lights[i];
4128 if (rtlight->corona_visibility <= 0)
4130 if (gl_flashblend.integer)
4131 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4133 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4139 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4140 typedef struct suffixinfo_s
4143 qboolean flipx, flipy, flipdiagonal;
4146 static suffixinfo_t suffix[3][6] =
4149 {"px", false, false, false},
4150 {"nx", false, false, false},
4151 {"py", false, false, false},
4152 {"ny", false, false, false},
4153 {"pz", false, false, false},
4154 {"nz", false, false, false}
4157 {"posx", false, false, false},
4158 {"negx", false, false, false},
4159 {"posy", false, false, false},
4160 {"negy", false, false, false},
4161 {"posz", false, false, false},
4162 {"negz", false, false, false}
4165 {"rt", true, false, true},
4166 {"lf", false, true, true},
4167 {"ft", true, true, false},
4168 {"bk", false, false, false},
4169 {"up", true, false, true},
4170 {"dn", true, false, true}
4174 static int componentorder[4] = {0, 1, 2, 3};
4176 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4178 int i, j, cubemapsize;
4179 unsigned char *cubemappixels, *image_buffer;
4180 rtexture_t *cubemaptexture;
4182 // must start 0 so the first loadimagepixels has no requested width/height
4184 cubemappixels = NULL;
4185 cubemaptexture = NULL;
4186 // keep trying different suffix groups (posx, px, rt) until one loads
4187 for (j = 0;j < 3 && !cubemappixels;j++)
4189 // load the 6 images in the suffix group
4190 for (i = 0;i < 6;i++)
4192 // generate an image name based on the base and and suffix
4193 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4195 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4197 // an image loaded, make sure width and height are equal
4198 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4200 // if this is the first image to load successfully, allocate the cubemap memory
4201 if (!cubemappixels && image_width >= 1)
4203 cubemapsize = image_width;
4204 // note this clears to black, so unavailable sides are black
4205 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4207 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4209 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);
4212 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4214 Mem_Free(image_buffer);
4218 // if a cubemap loaded, upload it
4221 if (developer_loading.integer)
4222 Con_Printf("loading cubemap \"%s\"\n", basename);
4224 if (!r_shadow_filters_texturepool)
4225 r_shadow_filters_texturepool = R_AllocTexturePool();
4226 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4227 Mem_Free(cubemappixels);
4231 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4232 if (developer_loading.integer)
4234 Con_Printf("(tried tried images ");
4235 for (j = 0;j < 3;j++)
4236 for (i = 0;i < 6;i++)
4237 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4238 Con_Print(" and was unable to find any of them).\n");
4241 return cubemaptexture;
4244 rtexture_t *R_Shadow_Cubemap(const char *basename)
4247 for (i = 0;i < numcubemaps;i++)
4248 if (!strcasecmp(cubemaps[i].basename, basename))
4249 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4250 if (i >= MAX_CUBEMAPS)
4251 return r_texture_whitecube;
4253 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4254 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4255 return cubemaps[i].texture;
4258 void R_Shadow_FreeCubemaps(void)
4261 for (i = 0;i < numcubemaps;i++)
4263 if (developer_loading.integer)
4264 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4265 if (cubemaps[i].texture)
4266 R_FreeTexture(cubemaps[i].texture);
4270 R_FreeTexturePool(&r_shadow_filters_texturepool);
4273 dlight_t *R_Shadow_NewWorldLight(void)
4275 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4278 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)
4281 // validate parameters
4282 if (style < 0 || style >= MAX_LIGHTSTYLES)
4284 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4290 // copy to light properties
4291 VectorCopy(origin, light->origin);
4292 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4293 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4294 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4295 light->color[0] = max(color[0], 0);
4296 light->color[1] = max(color[1], 0);
4297 light->color[2] = max(color[2], 0);
4298 light->radius = max(radius, 0);
4299 light->style = style;
4300 light->shadow = shadowenable;
4301 light->corona = corona;
4302 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4303 light->coronasizescale = coronasizescale;
4304 light->ambientscale = ambientscale;
4305 light->diffusescale = diffusescale;
4306 light->specularscale = specularscale;
4307 light->flags = flags;
4309 // update renderable light data
4310 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4311 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);
4314 void R_Shadow_FreeWorldLight(dlight_t *light)
4316 if (r_shadow_selectedlight == light)
4317 r_shadow_selectedlight = NULL;
4318 R_RTLight_Uncompile(&light->rtlight);
4319 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4322 void R_Shadow_ClearWorldLights(void)
4326 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4327 for (lightindex = 0;lightindex < range;lightindex++)
4329 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4331 R_Shadow_FreeWorldLight(light);
4333 r_shadow_selectedlight = NULL;
4334 R_Shadow_FreeCubemaps();
4337 void R_Shadow_SelectLight(dlight_t *light)
4339 if (r_shadow_selectedlight)
4340 r_shadow_selectedlight->selected = false;
4341 r_shadow_selectedlight = light;
4342 if (r_shadow_selectedlight)
4343 r_shadow_selectedlight->selected = true;
4346 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4348 // this is never batched (there can be only one)
4349 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);
4352 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4359 // this is never batched (due to the ent parameter changing every time)
4360 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4361 const dlight_t *light = (dlight_t *)ent;
4364 VectorScale(light->color, intensity, spritecolor);
4365 if (VectorLength(spritecolor) < 0.1732f)
4366 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4367 if (VectorLength(spritecolor) > 1.0f)
4368 VectorNormalize(spritecolor);
4370 // draw light sprite
4371 if (light->cubemapname[0] && !light->shadow)
4372 pic = r_editlights_sprcubemapnoshadowlight;
4373 else if (light->cubemapname[0])
4374 pic = r_editlights_sprcubemaplight;
4375 else if (!light->shadow)
4376 pic = r_editlights_sprnoshadowlight;
4378 pic = r_editlights_sprlight;
4379 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);
4380 // draw selection sprite if light is selected
4381 if (light->selected)
4382 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);
4383 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4386 void R_Shadow_DrawLightSprites(void)
4390 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4391 for (lightindex = 0;lightindex < range;lightindex++)
4393 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4395 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4397 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4400 void R_Shadow_SelectLightInView(void)
4402 float bestrating, rating, temp[3];
4406 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4409 for (lightindex = 0;lightindex < range;lightindex++)
4411 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4414 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4415 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4418 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4419 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)
4421 bestrating = rating;
4426 R_Shadow_SelectLight(best);
4429 void R_Shadow_LoadWorldLights(void)
4431 int n, a, style, shadow, flags;
4432 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4433 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4434 if (cl.worldmodel == NULL)
4436 Con_Print("No map loaded.\n");
4439 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4440 strlcat (name, ".rtlights", sizeof (name));
4441 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4451 for (;COM_Parse(t, true) && strcmp(
4452 if (COM_Parse(t, true))
4454 if (com_token[0] == '!')
4457 origin[0] = atof(com_token+1);
4460 origin[0] = atof(com_token);
4465 while (*s && *s != '\n' && *s != '\r')
4471 // check for modifier flags
4478 #if _MSC_VER >= 1400
4479 #define sscanf sscanf_s
4481 cubemapname[sizeof(cubemapname)-1] = 0;
4482 #if MAX_QPATH != 128
4483 #error update this code if MAX_QPATH changes
4485 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
4486 #if _MSC_VER >= 1400
4487 , sizeof(cubemapname)
4489 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4492 flags = LIGHTFLAG_REALTIMEMODE;
4500 coronasizescale = 0.25f;
4502 VectorClear(angles);
4505 if (a < 9 || !strcmp(cubemapname, "\"\""))
4507 // remove quotes on cubemapname
4508 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4511 namelen = strlen(cubemapname) - 2;
4512 memmove(cubemapname, cubemapname + 1, namelen);
4513 cubemapname[namelen] = '\0';
4517 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);
4520 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4528 Con_Printf("invalid rtlights file \"%s\"\n", name);
4529 Mem_Free(lightsstring);
4533 void R_Shadow_SaveWorldLights(void)
4537 size_t bufchars, bufmaxchars;
4539 char name[MAX_QPATH];
4540 char line[MAX_INPUTLINE];
4541 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4542 // I hate lines which are 3 times my screen size :( --blub
4545 if (cl.worldmodel == NULL)
4547 Con_Print("No map loaded.\n");
4550 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4551 strlcat (name, ".rtlights", sizeof (name));
4552 bufchars = bufmaxchars = 0;
4554 for (lightindex = 0;lightindex < range;lightindex++)
4556 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4559 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4560 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);
4561 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4562 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]);
4564 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);
4565 if (bufchars + strlen(line) > bufmaxchars)
4567 bufmaxchars = bufchars + strlen(line) + 2048;
4569 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4573 memcpy(buf, oldbuf, bufchars);
4579 memcpy(buf + bufchars, line, strlen(line));
4580 bufchars += strlen(line);
4584 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4589 void R_Shadow_LoadLightsFile(void)
4592 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4593 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4594 if (cl.worldmodel == NULL)
4596 Con_Print("No map loaded.\n");
4599 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4600 strlcat (name, ".lights", sizeof (name));
4601 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4609 while (*s && *s != '\n' && *s != '\r')
4615 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);
4619 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);
4622 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4623 radius = bound(15, radius, 4096);
4624 VectorScale(color, (2.0f / (8388608.0f)), color);
4625 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4633 Con_Printf("invalid lights file \"%s\"\n", name);
4634 Mem_Free(lightsstring);
4638 // tyrlite/hmap2 light types in the delay field
4639 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4641 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4643 int entnum, style, islight, skin, pflags, effects, type, n;
4646 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4647 char key[256], value[MAX_INPUTLINE];
4649 if (cl.worldmodel == NULL)
4651 Con_Print("No map loaded.\n");
4654 // try to load a .ent file first
4655 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4656 strlcat (key, ".ent", sizeof (key));
4657 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4658 // and if that is not found, fall back to the bsp file entity string
4660 data = cl.worldmodel->brush.entities;
4663 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4665 type = LIGHTTYPE_MINUSX;
4666 origin[0] = origin[1] = origin[2] = 0;
4667 originhack[0] = originhack[1] = originhack[2] = 0;
4668 angles[0] = angles[1] = angles[2] = 0;
4669 color[0] = color[1] = color[2] = 1;
4670 light[0] = light[1] = light[2] = 1;light[3] = 300;
4671 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4681 if (!COM_ParseToken_Simple(&data, false, false))
4683 if (com_token[0] == '}')
4684 break; // end of entity
4685 if (com_token[0] == '_')
4686 strlcpy(key, com_token + 1, sizeof(key));
4688 strlcpy(key, com_token, sizeof(key));
4689 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4690 key[strlen(key)-1] = 0;
4691 if (!COM_ParseToken_Simple(&data, false, false))
4693 strlcpy(value, com_token, sizeof(value));
4695 // now that we have the key pair worked out...
4696 if (!strcmp("light", key))
4698 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4702 light[0] = vec[0] * (1.0f / 256.0f);
4703 light[1] = vec[0] * (1.0f / 256.0f);
4704 light[2] = vec[0] * (1.0f / 256.0f);
4710 light[0] = vec[0] * (1.0f / 255.0f);
4711 light[1] = vec[1] * (1.0f / 255.0f);
4712 light[2] = vec[2] * (1.0f / 255.0f);
4716 else if (!strcmp("delay", key))
4718 else if (!strcmp("origin", key))
4719 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4720 else if (!strcmp("angle", key))
4721 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4722 else if (!strcmp("angles", key))
4723 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4724 else if (!strcmp("color", key))
4725 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4726 else if (!strcmp("wait", key))
4727 fadescale = atof(value);
4728 else if (!strcmp("classname", key))
4730 if (!strncmp(value, "light", 5))
4733 if (!strcmp(value, "light_fluoro"))
4738 overridecolor[0] = 1;
4739 overridecolor[1] = 1;
4740 overridecolor[2] = 1;
4742 if (!strcmp(value, "light_fluorospark"))
4747 overridecolor[0] = 1;
4748 overridecolor[1] = 1;
4749 overridecolor[2] = 1;
4751 if (!strcmp(value, "light_globe"))
4756 overridecolor[0] = 1;
4757 overridecolor[1] = 0.8;
4758 overridecolor[2] = 0.4;
4760 if (!strcmp(value, "light_flame_large_yellow"))
4765 overridecolor[0] = 1;
4766 overridecolor[1] = 0.5;
4767 overridecolor[2] = 0.1;
4769 if (!strcmp(value, "light_flame_small_yellow"))
4774 overridecolor[0] = 1;
4775 overridecolor[1] = 0.5;
4776 overridecolor[2] = 0.1;
4778 if (!strcmp(value, "light_torch_small_white"))
4783 overridecolor[0] = 1;
4784 overridecolor[1] = 0.5;
4785 overridecolor[2] = 0.1;
4787 if (!strcmp(value, "light_torch_small_walltorch"))
4792 overridecolor[0] = 1;
4793 overridecolor[1] = 0.5;
4794 overridecolor[2] = 0.1;
4798 else if (!strcmp("style", key))
4799 style = atoi(value);
4800 else if (!strcmp("skin", key))
4801 skin = (int)atof(value);
4802 else if (!strcmp("pflags", key))
4803 pflags = (int)atof(value);
4804 else if (!strcmp("effects", key))
4805 effects = (int)atof(value);
4806 else if (cl.worldmodel->type == mod_brushq3)
4808 if (!strcmp("scale", key))
4809 lightscale = atof(value);
4810 if (!strcmp("fade", key))
4811 fadescale = atof(value);
4816 if (lightscale <= 0)
4820 if (color[0] == color[1] && color[0] == color[2])
4822 color[0] *= overridecolor[0];
4823 color[1] *= overridecolor[1];
4824 color[2] *= overridecolor[2];
4826 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4827 color[0] = color[0] * light[0];
4828 color[1] = color[1] * light[1];
4829 color[2] = color[2] * light[2];
4832 case LIGHTTYPE_MINUSX:
4834 case LIGHTTYPE_RECIPX:
4836 VectorScale(color, (1.0f / 16.0f), color);
4838 case LIGHTTYPE_RECIPXX:
4840 VectorScale(color, (1.0f / 16.0f), color);
4843 case LIGHTTYPE_NONE:
4847 case LIGHTTYPE_MINUSXX:
4850 VectorAdd(origin, originhack, origin);
4852 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);
4855 Mem_Free(entfiledata);
4859 void R_Shadow_SetCursorLocationForView(void)
4862 vec3_t dest, endpos;
4864 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4865 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4866 if (trace.fraction < 1)
4868 dist = trace.fraction * r_editlights_cursordistance.value;
4869 push = r_editlights_cursorpushback.value;
4873 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4874 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4878 VectorClear( endpos );
4880 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4881 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4882 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4885 void R_Shadow_UpdateWorldLightSelection(void)
4887 if (r_editlights.integer)
4889 R_Shadow_SetCursorLocationForView();
4890 R_Shadow_SelectLightInView();
4893 R_Shadow_SelectLight(NULL);
4896 void R_Shadow_EditLights_Clear_f(void)
4898 R_Shadow_ClearWorldLights();
4901 void R_Shadow_EditLights_Reload_f(void)
4905 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4906 R_Shadow_ClearWorldLights();
4907 R_Shadow_LoadWorldLights();
4908 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4910 R_Shadow_LoadLightsFile();
4911 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4912 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4916 void R_Shadow_EditLights_Save_f(void)
4920 R_Shadow_SaveWorldLights();
4923 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4925 R_Shadow_ClearWorldLights();
4926 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4929 void R_Shadow_EditLights_ImportLightsFile_f(void)
4931 R_Shadow_ClearWorldLights();
4932 R_Shadow_LoadLightsFile();
4935 void R_Shadow_EditLights_Spawn_f(void)
4938 if (!r_editlights.integer)
4940 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4943 if (Cmd_Argc() != 1)
4945 Con_Print("r_editlights_spawn does not take parameters\n");
4948 color[0] = color[1] = color[2] = 1;
4949 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4952 void R_Shadow_EditLights_Edit_f(void)
4954 vec3_t origin, angles, color;
4955 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4956 int style, shadows, flags, normalmode, realtimemode;
4957 char cubemapname[MAX_INPUTLINE];
4958 if (!r_editlights.integer)
4960 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4963 if (!r_shadow_selectedlight)
4965 Con_Print("No selected light.\n");
4968 VectorCopy(r_shadow_selectedlight->origin, origin);
4969 VectorCopy(r_shadow_selectedlight->angles, angles);
4970 VectorCopy(r_shadow_selectedlight->color, color);
4971 radius = r_shadow_selectedlight->radius;
4972 style = r_shadow_selectedlight->style;
4973 if (r_shadow_selectedlight->cubemapname)
4974 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4977 shadows = r_shadow_selectedlight->shadow;
4978 corona = r_shadow_selectedlight->corona;
4979 coronasizescale = r_shadow_selectedlight->coronasizescale;
4980 ambientscale = r_shadow_selectedlight->ambientscale;
4981 diffusescale = r_shadow_selectedlight->diffusescale;
4982 specularscale = r_shadow_selectedlight->specularscale;
4983 flags = r_shadow_selectedlight->flags;
4984 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4985 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4986 if (!strcmp(Cmd_Argv(1), "origin"))
4988 if (Cmd_Argc() != 5)
4990 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4993 origin[0] = atof(Cmd_Argv(2));
4994 origin[1] = atof(Cmd_Argv(3));
4995 origin[2] = atof(Cmd_Argv(4));
4997 else if (!strcmp(Cmd_Argv(1), "originx"))
4999 if (Cmd_Argc() != 3)
5001 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5004 origin[0] = atof(Cmd_Argv(2));
5006 else if (!strcmp(Cmd_Argv(1), "originy"))
5008 if (Cmd_Argc() != 3)
5010 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5013 origin[1] = atof(Cmd_Argv(2));
5015 else if (!strcmp(Cmd_Argv(1), "originz"))
5017 if (Cmd_Argc() != 3)
5019 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5022 origin[2] = atof(Cmd_Argv(2));
5024 else if (!strcmp(Cmd_Argv(1), "move"))
5026 if (Cmd_Argc() != 5)
5028 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5031 origin[0] += atof(Cmd_Argv(2));
5032 origin[1] += atof(Cmd_Argv(3));
5033 origin[2] += atof(Cmd_Argv(4));
5035 else if (!strcmp(Cmd_Argv(1), "movex"))
5037 if (Cmd_Argc() != 3)
5039 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5042 origin[0] += atof(Cmd_Argv(2));
5044 else if (!strcmp(Cmd_Argv(1), "movey"))
5046 if (Cmd_Argc() != 3)
5048 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5051 origin[1] += atof(Cmd_Argv(2));
5053 else if (!strcmp(Cmd_Argv(1), "movez"))
5055 if (Cmd_Argc() != 3)
5057 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5060 origin[2] += atof(Cmd_Argv(2));
5062 else if (!strcmp(Cmd_Argv(1), "angles"))
5064 if (Cmd_Argc() != 5)
5066 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5069 angles[0] = atof(Cmd_Argv(2));
5070 angles[1] = atof(Cmd_Argv(3));
5071 angles[2] = atof(Cmd_Argv(4));
5073 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5075 if (Cmd_Argc() != 3)
5077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5080 angles[0] = atof(Cmd_Argv(2));
5082 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5084 if (Cmd_Argc() != 3)
5086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5089 angles[1] = atof(Cmd_Argv(2));
5091 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5093 if (Cmd_Argc() != 3)
5095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5098 angles[2] = atof(Cmd_Argv(2));
5100 else if (!strcmp(Cmd_Argv(1), "color"))
5102 if (Cmd_Argc() != 5)
5104 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5107 color[0] = atof(Cmd_Argv(2));
5108 color[1] = atof(Cmd_Argv(3));
5109 color[2] = atof(Cmd_Argv(4));
5111 else if (!strcmp(Cmd_Argv(1), "radius"))
5113 if (Cmd_Argc() != 3)
5115 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5118 radius = atof(Cmd_Argv(2));
5120 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5122 if (Cmd_Argc() == 3)
5124 double scale = atof(Cmd_Argv(2));
5131 if (Cmd_Argc() != 5)
5133 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5136 color[0] *= atof(Cmd_Argv(2));
5137 color[1] *= atof(Cmd_Argv(3));
5138 color[2] *= atof(Cmd_Argv(4));
5141 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5143 if (Cmd_Argc() != 3)
5145 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5148 radius *= atof(Cmd_Argv(2));
5150 else if (!strcmp(Cmd_Argv(1), "style"))
5152 if (Cmd_Argc() != 3)
5154 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5157 style = atoi(Cmd_Argv(2));
5159 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5163 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5166 if (Cmd_Argc() == 3)
5167 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5171 else if (!strcmp(Cmd_Argv(1), "shadows"))
5173 if (Cmd_Argc() != 3)
5175 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5178 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5180 else if (!strcmp(Cmd_Argv(1), "corona"))
5182 if (Cmd_Argc() != 3)
5184 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5187 corona = atof(Cmd_Argv(2));
5189 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5191 if (Cmd_Argc() != 3)
5193 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5196 coronasizescale = atof(Cmd_Argv(2));
5198 else if (!strcmp(Cmd_Argv(1), "ambient"))
5200 if (Cmd_Argc() != 3)
5202 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5205 ambientscale = atof(Cmd_Argv(2));
5207 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5209 if (Cmd_Argc() != 3)
5211 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5214 diffusescale = atof(Cmd_Argv(2));
5216 else if (!strcmp(Cmd_Argv(1), "specular"))
5218 if (Cmd_Argc() != 3)
5220 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5223 specularscale = atof(Cmd_Argv(2));
5225 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5227 if (Cmd_Argc() != 3)
5229 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5232 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5234 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5236 if (Cmd_Argc() != 3)
5238 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5241 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5245 Con_Print("usage: r_editlights_edit [property] [value]\n");
5246 Con_Print("Selected light's properties:\n");
5247 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5248 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5249 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5250 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5251 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5252 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5253 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5254 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5255 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5256 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5257 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5258 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5259 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5260 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5263 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5264 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5267 void R_Shadow_EditLights_EditAll_f(void)
5273 if (!r_editlights.integer)
5275 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5279 // EditLights doesn't seem to have a "remove" command or something so:
5280 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5281 for (lightindex = 0;lightindex < range;lightindex++)
5283 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5286 R_Shadow_SelectLight(light);
5287 R_Shadow_EditLights_Edit_f();
5291 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5293 int lightnumber, lightcount;
5294 size_t lightindex, range;
5298 if (!r_editlights.integer)
5300 x = vid_conwidth.value - 240;
5302 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5305 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5306 for (lightindex = 0;lightindex < range;lightindex++)
5308 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5311 if (light == r_shadow_selectedlight)
5312 lightnumber = lightindex;
5315 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;
5316 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;
5318 if (r_shadow_selectedlight == NULL)
5320 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;
5321 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;
5322 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;
5323 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;
5324 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;
5325 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;
5326 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;
5327 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;
5328 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;
5329 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;
5330 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;
5331 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;
5332 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;
5333 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;
5334 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;
5337 void R_Shadow_EditLights_ToggleShadow_f(void)
5339 if (!r_editlights.integer)
5341 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5344 if (!r_shadow_selectedlight)
5346 Con_Print("No selected light.\n");
5349 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);
5352 void R_Shadow_EditLights_ToggleCorona_f(void)
5354 if (!r_editlights.integer)
5356 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5359 if (!r_shadow_selectedlight)
5361 Con_Print("No selected light.\n");
5364 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);
5367 void R_Shadow_EditLights_Remove_f(void)
5369 if (!r_editlights.integer)
5371 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5374 if (!r_shadow_selectedlight)
5376 Con_Print("No selected light.\n");
5379 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5380 r_shadow_selectedlight = NULL;
5383 void R_Shadow_EditLights_Help_f(void)
5386 "Documentation on r_editlights system:\n"
5388 "r_editlights : enable/disable editing mode\n"
5389 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5390 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5391 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5392 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5393 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5395 "r_editlights_help : this help\n"
5396 "r_editlights_clear : remove all lights\n"
5397 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5398 "r_editlights_save : save to .rtlights file\n"
5399 "r_editlights_spawn : create a light with default settings\n"
5400 "r_editlights_edit command : edit selected light - more documentation below\n"
5401 "r_editlights_remove : remove selected light\n"
5402 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5403 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5404 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5406 "origin x y z : set light location\n"
5407 "originx x: set x component of light location\n"
5408 "originy y: set y component of light location\n"
5409 "originz z: set z component of light location\n"
5410 "move x y z : adjust light location\n"
5411 "movex x: adjust x component of light location\n"
5412 "movey y: adjust y component of light location\n"
5413 "movez z: adjust z component of light location\n"
5414 "angles x y z : set light angles\n"
5415 "anglesx x: set x component of light angles\n"
5416 "anglesy y: set y component of light angles\n"
5417 "anglesz z: set z component of light angles\n"
5418 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5419 "radius radius : set radius (size) of light\n"
5420 "colorscale grey : multiply color of light (1 does nothing)\n"
5421 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5422 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5423 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5424 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5425 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5426 "shadows 1/0 : turn on/off shadows\n"
5427 "corona n : set corona intensity\n"
5428 "coronasize n : set corona size (0-1)\n"
5429 "ambient n : set ambient intensity (0-1)\n"
5430 "diffuse n : set diffuse intensity (0-1)\n"
5431 "specular n : set specular intensity (0-1)\n"
5432 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5433 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5434 "<nothing> : print light properties to console\n"
5438 void R_Shadow_EditLights_CopyInfo_f(void)
5440 if (!r_editlights.integer)
5442 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5445 if (!r_shadow_selectedlight)
5447 Con_Print("No selected light.\n");
5450 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5451 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5452 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5453 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5454 if (r_shadow_selectedlight->cubemapname)
5455 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5457 r_shadow_bufferlight.cubemapname[0] = 0;
5458 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5459 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5460 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5461 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5462 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5463 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5464 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5467 void R_Shadow_EditLights_PasteInfo_f(void)
5469 if (!r_editlights.integer)
5471 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5474 if (!r_shadow_selectedlight)
5476 Con_Print("No selected light.\n");
5479 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);
5482 void R_Shadow_EditLights_Init(void)
5484 Cvar_RegisterVariable(&r_editlights);
5485 Cvar_RegisterVariable(&r_editlights_cursordistance);
5486 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5487 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5488 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5489 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5490 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5491 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5492 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)");
5493 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5494 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5495 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5496 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)");
5497 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5498 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5499 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5500 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5501 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5502 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5503 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)");
5509 =============================================================================
5513 =============================================================================
5516 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5518 VectorClear(diffusecolor);
5519 VectorClear(diffusenormal);
5521 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5523 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5524 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5527 VectorSet(ambientcolor, 1, 1, 1);
5534 for (i = 0;i < r_refdef.scene.numlights;i++)
5536 light = r_refdef.scene.lights[i];
5537 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5538 f = 1 - VectorLength2(v);
5539 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5540 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);