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 float r_shadow_shadowmap_texturescale[4];
172 float r_shadow_shadowmap_parameters[4];
173 int r_shadow_drawbuffer;
174 int r_shadow_readbuffer;
175 GLuint r_shadow_fborectangle;
176 int r_shadow_shadowmode;
177 int r_shadow_shadowmapmaxsize;
178 int r_shadow_shadowmapfilter;
179 int r_shadow_shadowmapborder;
180 int r_shadow_lightscissor[4];
182 int maxshadowtriangles;
185 int maxshadowvertices;
186 float *shadowvertex3f;
199 int r_shadow_buffer_numleafpvsbytes;
200 unsigned char *r_shadow_buffer_visitingleafpvs;
201 unsigned char *r_shadow_buffer_leafpvs;
202 int *r_shadow_buffer_leaflist;
204 int r_shadow_buffer_numsurfacepvsbytes;
205 unsigned char *r_shadow_buffer_surfacepvs;
206 int *r_shadow_buffer_surfacelist;
208 int r_shadow_buffer_numshadowtrispvsbytes;
209 unsigned char *r_shadow_buffer_shadowtrispvs;
210 int r_shadow_buffer_numlighttrispvsbytes;
211 unsigned char *r_shadow_buffer_lighttrispvs;
213 rtexturepool_t *r_shadow_texturepool;
214 rtexture_t *r_shadow_attenuationgradienttexture;
215 rtexture_t *r_shadow_attenuation2dtexture;
216 rtexture_t *r_shadow_attenuation3dtexture;
217 rtexture_t *r_shadow_lightcorona;
218 rtexture_t *r_shadow_shadowmaprectangletexture;
219 rtexture_t *r_shadow_shadowmapcubeprojectiontexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
220 int r_shadow_shadowmapsize; // changes for each light based on distance
221 int r_shadow_shadowmaplod; // changes for each light based on distance
223 // lights are reloaded when this changes
224 char r_shadow_mapname[MAX_QPATH];
226 // used only for light filters (cubemaps)
227 rtexturepool_t *r_shadow_filters_texturepool;
229 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"};
230 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"};
231 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
232 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
233 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)"};
234 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"};
235 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
236 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
237 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
238 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
239 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
240 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
241 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
242 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
243 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
244 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)"};
245 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
246 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
247 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
248 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
249 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)"};
250 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"};
251 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
252 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
253 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"};
254 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
255 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
256 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)"};
257 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"};
258 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
259 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
260 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
261 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
262 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
263 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
264 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
265 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
266 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
267 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
268 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)"};
269 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)"};
270 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
271 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"};
272 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
273 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
274 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
275 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
276 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
277 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
278 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
279 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
280 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
281 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
283 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
284 #define ATTENTABLESIZE 256
285 // 1D gradient, 2D circle and 3D sphere attenuation textures
286 #define ATTEN1DSIZE 32
287 #define ATTEN2DSIZE 64
288 #define ATTEN3DSIZE 32
290 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
291 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
292 static float r_shadow_attentable[ATTENTABLESIZE+1];
294 rtlight_t *r_shadow_compilingrtlight;
295 static memexpandablearray_t r_shadow_worldlightsarray;
296 dlight_t *r_shadow_selectedlight;
297 dlight_t r_shadow_bufferlight;
298 vec3_t r_editlights_cursorlocation;
300 extern int con_vislines;
302 typedef struct cubemapinfo_s
309 #define MAX_CUBEMAPS 256
310 static int numcubemaps;
311 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
313 void R_Shadow_UncompileWorldLights(void);
314 void R_Shadow_ClearWorldLights(void);
315 void R_Shadow_SaveWorldLights(void);
316 void R_Shadow_LoadWorldLights(void);
317 void R_Shadow_LoadLightsFile(void);
318 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
319 void R_Shadow_EditLights_Reload_f(void);
320 void R_Shadow_ValidateCvars(void);
321 static void R_Shadow_MakeTextures(void);
323 // VorteX: custom editor light sprites
324 #define EDLIGHTSPRSIZE 8
325 cachepic_t *r_editlights_sprcursor;
326 cachepic_t *r_editlights_sprlight;
327 cachepic_t *r_editlights_sprnoshadowlight;
328 cachepic_t *r_editlights_sprcubemaplight;
329 cachepic_t *r_editlights_sprcubemapnoshadowlight;
330 cachepic_t *r_editlights_sprselection;
332 void R_Shadow_FreeShadowMaps(void)
336 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
337 r_shadow_shadowmode = r_shadow_shadowmapping.integer;
338 r_shadow_shadowmapfilter = r_shadow_shadowmapping_filterquality.integer;
339 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
340 r_shadow_shadowmaplod = -1;
343 if (r_shadow_fborectangle)
344 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
345 r_shadow_fborectangle = 0;
348 if (r_shadow_shadowmaprectangletexture)
349 R_FreeTexture(r_shadow_shadowmaprectangletexture);
350 r_shadow_shadowmaprectangletexture = NULL;
352 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
353 if (r_shadow_shadowmapcubeprojectiontexture[i])
354 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture[i]);
355 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
360 void r_shadow_start(void)
362 // allocate vertex processing arrays
364 r_shadow_attenuationgradienttexture = NULL;
365 r_shadow_attenuation2dtexture = NULL;
366 r_shadow_attenuation3dtexture = NULL;
367 r_shadow_shadowmode = 0;
368 r_shadow_shadowmaprectangletexture = NULL;
369 memset(r_shadow_shadowmapcubeprojectiontexture, 0, sizeof(r_shadow_shadowmapcubeprojectiontexture));
370 r_shadow_shadowmapmaxsize = 0;
371 r_shadow_shadowmapsize = 0;
372 r_shadow_shadowmaplod = 0;
373 r_shadow_shadowmapfilter = 0;
374 r_shadow_fborectangle = 0;
376 R_Shadow_FreeShadowMaps();
378 r_shadow_texturepool = NULL;
379 r_shadow_filters_texturepool = NULL;
380 R_Shadow_ValidateCvars();
381 R_Shadow_MakeTextures();
382 maxshadowtriangles = 0;
383 shadowelements = NULL;
384 maxshadowvertices = 0;
385 shadowvertex3f = NULL;
393 shadowmarklist = NULL;
395 r_shadow_buffer_numleafpvsbytes = 0;
396 r_shadow_buffer_visitingleafpvs = NULL;
397 r_shadow_buffer_leafpvs = NULL;
398 r_shadow_buffer_leaflist = NULL;
399 r_shadow_buffer_numsurfacepvsbytes = 0;
400 r_shadow_buffer_surfacepvs = NULL;
401 r_shadow_buffer_surfacelist = NULL;
402 r_shadow_buffer_numshadowtrispvsbytes = 0;
403 r_shadow_buffer_shadowtrispvs = NULL;
404 r_shadow_buffer_numlighttrispvsbytes = 0;
405 r_shadow_buffer_lighttrispvs = NULL;
408 void r_shadow_shutdown(void)
411 R_Shadow_UncompileWorldLights();
413 R_Shadow_FreeShadowMaps();
417 r_shadow_attenuationgradienttexture = NULL;
418 r_shadow_attenuation2dtexture = NULL;
419 r_shadow_attenuation3dtexture = NULL;
420 R_FreeTexturePool(&r_shadow_texturepool);
421 R_FreeTexturePool(&r_shadow_filters_texturepool);
422 maxshadowtriangles = 0;
424 Mem_Free(shadowelements);
425 shadowelements = NULL;
427 Mem_Free(shadowvertex3f);
428 shadowvertex3f = NULL;
431 Mem_Free(vertexupdate);
434 Mem_Free(vertexremap);
440 Mem_Free(shadowmark);
443 Mem_Free(shadowmarklist);
444 shadowmarklist = NULL;
446 r_shadow_buffer_numleafpvsbytes = 0;
447 if (r_shadow_buffer_visitingleafpvs)
448 Mem_Free(r_shadow_buffer_visitingleafpvs);
449 r_shadow_buffer_visitingleafpvs = NULL;
450 if (r_shadow_buffer_leafpvs)
451 Mem_Free(r_shadow_buffer_leafpvs);
452 r_shadow_buffer_leafpvs = NULL;
453 if (r_shadow_buffer_leaflist)
454 Mem_Free(r_shadow_buffer_leaflist);
455 r_shadow_buffer_leaflist = NULL;
456 r_shadow_buffer_numsurfacepvsbytes = 0;
457 if (r_shadow_buffer_surfacepvs)
458 Mem_Free(r_shadow_buffer_surfacepvs);
459 r_shadow_buffer_surfacepvs = NULL;
460 if (r_shadow_buffer_surfacelist)
461 Mem_Free(r_shadow_buffer_surfacelist);
462 r_shadow_buffer_surfacelist = NULL;
463 r_shadow_buffer_numshadowtrispvsbytes = 0;
464 if (r_shadow_buffer_shadowtrispvs)
465 Mem_Free(r_shadow_buffer_shadowtrispvs);
466 r_shadow_buffer_numlighttrispvsbytes = 0;
467 if (r_shadow_buffer_lighttrispvs)
468 Mem_Free(r_shadow_buffer_lighttrispvs);
471 void r_shadow_newmap(void)
473 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
474 R_Shadow_EditLights_Reload_f();
477 void R_Shadow_Help_f(void)
480 "Documentation on r_shadow system:\n"
482 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
483 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
484 "r_shadow_debuglight : render only this light number (-1 = all)\n"
485 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
486 "r_shadow_gloss2intensity : brightness of forced gloss\n"
487 "r_shadow_glossintensity : brightness of textured gloss\n"
488 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
489 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
490 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
491 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
492 "r_shadow_portallight : use portal visibility for static light precomputation\n"
493 "r_shadow_projectdistance : shadow volume projection distance\n"
494 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
495 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
496 "r_shadow_realtime_world : use high quality world lighting mode\n"
497 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
498 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
499 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
500 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
501 "r_shadow_scissor : use scissor optimization\n"
502 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
503 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
504 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
505 "r_showlighting : useful for performance testing; bright = slow!\n"
506 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
508 "r_shadow_help : this help\n"
512 void R_Shadow_Init(void)
514 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
515 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
516 Cvar_RegisterVariable(&r_shadow_usenormalmap);
517 Cvar_RegisterVariable(&r_shadow_debuglight);
518 Cvar_RegisterVariable(&r_shadow_gloss);
519 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
520 Cvar_RegisterVariable(&r_shadow_glossintensity);
521 Cvar_RegisterVariable(&r_shadow_glossexponent);
522 Cvar_RegisterVariable(&r_shadow_glossexact);
523 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
524 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
525 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
526 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
527 Cvar_RegisterVariable(&r_shadow_portallight);
528 Cvar_RegisterVariable(&r_shadow_projectdistance);
529 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
530 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
531 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
532 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
533 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
534 Cvar_RegisterVariable(&r_shadow_realtime_world);
535 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
536 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
537 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
538 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
539 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
540 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
541 Cvar_RegisterVariable(&r_shadow_scissor);
542 Cvar_RegisterVariable(&r_shadow_shadowmapping);
543 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
544 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
545 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
546 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
547 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
548 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
549 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
550 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
551 Cvar_RegisterVariable(&r_shadow_culltriangles);
552 Cvar_RegisterVariable(&r_shadow_polygonfactor);
553 Cvar_RegisterVariable(&r_shadow_polygonoffset);
554 Cvar_RegisterVariable(&r_shadow_texture3d);
555 Cvar_RegisterVariable(&r_coronas);
556 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
557 Cvar_RegisterVariable(&r_coronas_occlusionquery);
558 Cvar_RegisterVariable(&gl_flashblend);
559 Cvar_RegisterVariable(&gl_ext_separatestencil);
560 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
561 if (gamemode == GAME_TENEBRAE)
563 Cvar_SetValue("r_shadow_gloss", 2);
564 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
566 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
567 R_Shadow_EditLights_Init();
568 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
569 maxshadowtriangles = 0;
570 shadowelements = NULL;
571 maxshadowvertices = 0;
572 shadowvertex3f = NULL;
580 shadowmarklist = NULL;
582 r_shadow_buffer_numleafpvsbytes = 0;
583 r_shadow_buffer_visitingleafpvs = NULL;
584 r_shadow_buffer_leafpvs = NULL;
585 r_shadow_buffer_leaflist = NULL;
586 r_shadow_buffer_numsurfacepvsbytes = 0;
587 r_shadow_buffer_surfacepvs = NULL;
588 r_shadow_buffer_surfacelist = NULL;
589 r_shadow_buffer_shadowtrispvs = NULL;
590 r_shadow_buffer_lighttrispvs = NULL;
591 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
594 matrix4x4_t matrix_attenuationxyz =
597 {0.5, 0.0, 0.0, 0.5},
598 {0.0, 0.5, 0.0, 0.5},
599 {0.0, 0.0, 0.5, 0.5},
604 matrix4x4_t matrix_attenuationz =
607 {0.0, 0.0, 0.5, 0.5},
608 {0.0, 0.0, 0.0, 0.5},
609 {0.0, 0.0, 0.0, 0.5},
614 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
616 // make sure shadowelements is big enough for this volume
617 if (maxshadowtriangles < numtriangles)
619 maxshadowtriangles = numtriangles;
621 Mem_Free(shadowelements);
622 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
624 // make sure shadowvertex3f is big enough for this volume
625 if (maxshadowvertices < numvertices)
627 maxshadowvertices = numvertices;
629 Mem_Free(shadowvertex3f);
630 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
634 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
636 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
637 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
638 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
639 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
640 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
642 if (r_shadow_buffer_visitingleafpvs)
643 Mem_Free(r_shadow_buffer_visitingleafpvs);
644 if (r_shadow_buffer_leafpvs)
645 Mem_Free(r_shadow_buffer_leafpvs);
646 if (r_shadow_buffer_leaflist)
647 Mem_Free(r_shadow_buffer_leaflist);
648 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
649 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
650 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
651 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
653 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
655 if (r_shadow_buffer_surfacepvs)
656 Mem_Free(r_shadow_buffer_surfacepvs);
657 if (r_shadow_buffer_surfacelist)
658 Mem_Free(r_shadow_buffer_surfacelist);
659 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
660 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
661 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
663 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
665 if (r_shadow_buffer_shadowtrispvs)
666 Mem_Free(r_shadow_buffer_shadowtrispvs);
667 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
668 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
670 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
672 if (r_shadow_buffer_lighttrispvs)
673 Mem_Free(r_shadow_buffer_lighttrispvs);
674 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
675 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
679 void R_Shadow_PrepareShadowMark(int numtris)
681 // make sure shadowmark is big enough for this volume
682 if (maxshadowmark < numtris)
684 maxshadowmark = numtris;
686 Mem_Free(shadowmark);
688 Mem_Free(shadowmarklist);
689 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
690 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
694 // if shadowmarkcount wrapped we clear the array and adjust accordingly
695 if (shadowmarkcount == 0)
698 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
703 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)
706 int outtriangles = 0, outvertices = 0;
709 float ratio, direction[3], projectvector[3];
711 if (projectdirection)
712 VectorScale(projectdirection, projectdistance, projectvector);
714 VectorClear(projectvector);
716 // create the vertices
717 if (projectdirection)
719 for (i = 0;i < numshadowmarktris;i++)
721 element = inelement3i + shadowmarktris[i] * 3;
722 for (j = 0;j < 3;j++)
724 if (vertexupdate[element[j]] != vertexupdatenum)
726 vertexupdate[element[j]] = vertexupdatenum;
727 vertexremap[element[j]] = outvertices;
728 vertex = invertex3f + element[j] * 3;
729 // project one copy of the vertex according to projectvector
730 VectorCopy(vertex, outvertex3f);
731 VectorAdd(vertex, projectvector, (outvertex3f + 3));
740 for (i = 0;i < numshadowmarktris;i++)
742 element = inelement3i + shadowmarktris[i] * 3;
743 for (j = 0;j < 3;j++)
745 if (vertexupdate[element[j]] != vertexupdatenum)
747 vertexupdate[element[j]] = vertexupdatenum;
748 vertexremap[element[j]] = outvertices;
749 vertex = invertex3f + element[j] * 3;
750 // project one copy of the vertex to the sphere radius of the light
751 // (FIXME: would projecting it to the light box be better?)
752 VectorSubtract(vertex, projectorigin, direction);
753 ratio = projectdistance / VectorLength(direction);
754 VectorCopy(vertex, outvertex3f);
755 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
763 if (r_shadow_frontsidecasting.integer)
765 for (i = 0;i < numshadowmarktris;i++)
767 int remappedelement[3];
769 const int *neighbortriangle;
771 markindex = shadowmarktris[i] * 3;
772 element = inelement3i + markindex;
773 neighbortriangle = inneighbor3i + markindex;
774 // output the front and back triangles
775 outelement3i[0] = vertexremap[element[0]];
776 outelement3i[1] = vertexremap[element[1]];
777 outelement3i[2] = vertexremap[element[2]];
778 outelement3i[3] = vertexremap[element[2]] + 1;
779 outelement3i[4] = vertexremap[element[1]] + 1;
780 outelement3i[5] = vertexremap[element[0]] + 1;
784 // output the sides (facing outward from this triangle)
785 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
787 remappedelement[0] = vertexremap[element[0]];
788 remappedelement[1] = vertexremap[element[1]];
789 outelement3i[0] = remappedelement[1];
790 outelement3i[1] = remappedelement[0];
791 outelement3i[2] = remappedelement[0] + 1;
792 outelement3i[3] = remappedelement[1];
793 outelement3i[4] = remappedelement[0] + 1;
794 outelement3i[5] = remappedelement[1] + 1;
799 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
801 remappedelement[1] = vertexremap[element[1]];
802 remappedelement[2] = vertexremap[element[2]];
803 outelement3i[0] = remappedelement[2];
804 outelement3i[1] = remappedelement[1];
805 outelement3i[2] = remappedelement[1] + 1;
806 outelement3i[3] = remappedelement[2];
807 outelement3i[4] = remappedelement[1] + 1;
808 outelement3i[5] = remappedelement[2] + 1;
813 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
815 remappedelement[0] = vertexremap[element[0]];
816 remappedelement[2] = vertexremap[element[2]];
817 outelement3i[0] = remappedelement[0];
818 outelement3i[1] = remappedelement[2];
819 outelement3i[2] = remappedelement[2] + 1;
820 outelement3i[3] = remappedelement[0];
821 outelement3i[4] = remappedelement[2] + 1;
822 outelement3i[5] = remappedelement[0] + 1;
831 for (i = 0;i < numshadowmarktris;i++)
833 int remappedelement[3];
835 const int *neighbortriangle;
837 markindex = shadowmarktris[i] * 3;
838 element = inelement3i + markindex;
839 neighbortriangle = inneighbor3i + markindex;
840 // output the front and back triangles
841 outelement3i[0] = vertexremap[element[2]];
842 outelement3i[1] = vertexremap[element[1]];
843 outelement3i[2] = vertexremap[element[0]];
844 outelement3i[3] = vertexremap[element[0]] + 1;
845 outelement3i[4] = vertexremap[element[1]] + 1;
846 outelement3i[5] = vertexremap[element[2]] + 1;
850 // output the sides (facing outward from this triangle)
851 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
853 remappedelement[0] = vertexremap[element[0]];
854 remappedelement[1] = vertexremap[element[1]];
855 outelement3i[0] = remappedelement[0];
856 outelement3i[1] = remappedelement[1];
857 outelement3i[2] = remappedelement[1] + 1;
858 outelement3i[3] = remappedelement[0];
859 outelement3i[4] = remappedelement[1] + 1;
860 outelement3i[5] = remappedelement[0] + 1;
865 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
867 remappedelement[1] = vertexremap[element[1]];
868 remappedelement[2] = vertexremap[element[2]];
869 outelement3i[0] = remappedelement[1];
870 outelement3i[1] = remappedelement[2];
871 outelement3i[2] = remappedelement[2] + 1;
872 outelement3i[3] = remappedelement[1];
873 outelement3i[4] = remappedelement[2] + 1;
874 outelement3i[5] = remappedelement[1] + 1;
879 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
881 remappedelement[0] = vertexremap[element[0]];
882 remappedelement[2] = vertexremap[element[2]];
883 outelement3i[0] = remappedelement[2];
884 outelement3i[1] = remappedelement[0];
885 outelement3i[2] = remappedelement[0] + 1;
886 outelement3i[3] = remappedelement[2];
887 outelement3i[4] = remappedelement[0] + 1;
888 outelement3i[5] = remappedelement[2] + 1;
896 *outnumvertices = outvertices;
900 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)
903 int outtriangles = 0, outvertices = 0;
906 float ratio, direction[3], projectvector[3];
909 if (projectdirection)
910 VectorScale(projectdirection, projectdistance, projectvector);
912 VectorClear(projectvector);
914 for (i = 0;i < numshadowmarktris;i++)
916 int remappedelement[3];
918 const int *neighbortriangle;
920 markindex = shadowmarktris[i] * 3;
921 neighbortriangle = inneighbor3i + markindex;
922 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
923 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
924 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
925 if (side[0] + side[1] + side[2] == 0)
929 element = inelement3i + markindex;
931 // create the vertices
932 for (j = 0;j < 3;j++)
934 if (side[j] + side[j+1] == 0)
937 if (vertexupdate[k] != vertexupdatenum)
939 vertexupdate[k] = vertexupdatenum;
940 vertexremap[k] = outvertices;
941 vertex = invertex3f + k * 3;
942 VectorCopy(vertex, outvertex3f);
943 if (projectdirection)
945 // project one copy of the vertex according to projectvector
946 VectorAdd(vertex, projectvector, (outvertex3f + 3));
950 // project one copy of the vertex to the sphere radius of the light
951 // (FIXME: would projecting it to the light box be better?)
952 VectorSubtract(vertex, projectorigin, direction);
953 ratio = projectdistance / VectorLength(direction);
954 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
961 // output the sides (facing outward from this triangle)
964 remappedelement[0] = vertexremap[element[0]];
965 remappedelement[1] = vertexremap[element[1]];
966 outelement3i[0] = remappedelement[1];
967 outelement3i[1] = remappedelement[0];
968 outelement3i[2] = remappedelement[0] + 1;
969 outelement3i[3] = remappedelement[1];
970 outelement3i[4] = remappedelement[0] + 1;
971 outelement3i[5] = remappedelement[1] + 1;
978 remappedelement[1] = vertexremap[element[1]];
979 remappedelement[2] = vertexremap[element[2]];
980 outelement3i[0] = remappedelement[2];
981 outelement3i[1] = remappedelement[1];
982 outelement3i[2] = remappedelement[1] + 1;
983 outelement3i[3] = remappedelement[2];
984 outelement3i[4] = remappedelement[1] + 1;
985 outelement3i[5] = remappedelement[2] + 1;
992 remappedelement[0] = vertexremap[element[0]];
993 remappedelement[2] = vertexremap[element[2]];
994 outelement3i[0] = remappedelement[0];
995 outelement3i[1] = remappedelement[2];
996 outelement3i[2] = remappedelement[2] + 1;
997 outelement3i[3] = remappedelement[0];
998 outelement3i[4] = remappedelement[2] + 1;
999 outelement3i[5] = remappedelement[0] + 1;
1006 *outnumvertices = outvertices;
1007 return outtriangles;
1010 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)
1016 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1018 tend = firsttriangle + numtris;
1019 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1021 // surface box entirely inside light box, no box cull
1022 if (projectdirection)
1024 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1026 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1027 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1028 shadowmarklist[numshadowmark++] = t;
1033 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1034 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1035 shadowmarklist[numshadowmark++] = t;
1040 // surface box not entirely inside light box, cull each triangle
1041 if (projectdirection)
1043 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1045 v[0] = invertex3f + e[0] * 3;
1046 v[1] = invertex3f + e[1] * 3;
1047 v[2] = invertex3f + e[2] * 3;
1048 TriangleNormal(v[0], v[1], v[2], normal);
1049 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1050 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1051 shadowmarklist[numshadowmark++] = t;
1056 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1058 v[0] = invertex3f + e[0] * 3;
1059 v[1] = invertex3f + e[1] * 3;
1060 v[2] = invertex3f + e[2] * 3;
1061 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1062 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1063 shadowmarklist[numshadowmark++] = t;
1069 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1074 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1076 // check if the shadow volume intersects the near plane
1078 // a ray between the eye and light origin may intersect the caster,
1079 // indicating that the shadow may touch the eye location, however we must
1080 // test the near plane (a polygon), not merely the eye location, so it is
1081 // easiest to enlarge the caster bounding shape slightly for this.
1087 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)
1089 int i, tris, outverts;
1090 if (projectdistance < 0.1)
1092 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1095 if (!numverts || !nummarktris)
1097 // make sure shadowelements is big enough for this volume
1098 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1099 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1101 if (maxvertexupdate < numverts)
1103 maxvertexupdate = numverts;
1105 Mem_Free(vertexupdate);
1107 Mem_Free(vertexremap);
1108 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1109 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1110 vertexupdatenum = 0;
1113 if (vertexupdatenum == 0)
1115 vertexupdatenum = 1;
1116 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1117 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1120 for (i = 0;i < nummarktris;i++)
1121 shadowmark[marktris[i]] = shadowmarkcount;
1123 if (r_shadow_compilingrtlight)
1125 // if we're compiling an rtlight, capture the mesh
1126 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1127 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1128 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1129 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1133 // decide which type of shadow to generate and set stencil mode
1134 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1135 // generate the sides or a solid volume, depending on type
1136 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1137 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1139 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1140 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1141 r_refdef.stats.lights_shadowtriangles += tris;
1143 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1144 GL_LockArrays(0, outverts);
1145 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1147 // increment stencil if frontface is infront of depthbuffer
1148 GL_CullFace(r_refdef.view.cullface_front);
1149 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1150 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1151 // decrement stencil if backface is infront of depthbuffer
1152 GL_CullFace(r_refdef.view.cullface_back);
1153 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1155 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1157 // decrement stencil if backface is behind depthbuffer
1158 GL_CullFace(r_refdef.view.cullface_front);
1159 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1160 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1161 // increment stencil if frontface is behind depthbuffer
1162 GL_CullFace(r_refdef.view.cullface_back);
1163 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1165 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1166 GL_LockArrays(0, 0);
1171 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)
1173 int i, tris = nummarktris;
1176 if (!numverts || !nummarktris)
1178 // make sure shadowelements is big enough for this mesh
1179 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1180 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1182 // gather up the (sparse) triangles into one array
1183 outelement3i = shadowelements;
1184 for (i = 0;i < nummarktris;i++)
1186 element = elements + marktris[i] * 3;
1187 outelement3i[0] = element[0];
1188 outelement3i[1] = element[1];
1189 outelement3i[2] = element[2];
1193 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1194 r_refdef.stats.lights_shadowtriangles += tris;
1195 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1196 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1199 static void R_Shadow_MakeTextures_MakeCorona(void)
1203 unsigned char pixels[32][32][4];
1204 for (y = 0;y < 32;y++)
1206 dy = (y - 15.5f) * (1.0f / 16.0f);
1207 for (x = 0;x < 32;x++)
1209 dx = (x - 15.5f) * (1.0f / 16.0f);
1210 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1211 a = bound(0, a, 255);
1212 pixels[y][x][0] = a;
1213 pixels[y][x][1] = a;
1214 pixels[y][x][2] = a;
1215 pixels[y][x][3] = 255;
1218 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1221 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1223 float dist = sqrt(x*x+y*y+z*z);
1224 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1225 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1226 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1229 static void R_Shadow_MakeTextures(void)
1232 float intensity, dist;
1234 R_FreeTexturePool(&r_shadow_texturepool);
1235 r_shadow_texturepool = R_AllocTexturePool();
1236 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1237 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1238 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1239 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1240 for (x = 0;x <= ATTENTABLESIZE;x++)
1242 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1243 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1244 r_shadow_attentable[x] = bound(0, intensity, 1);
1246 // 1D gradient texture
1247 for (x = 0;x < ATTEN1DSIZE;x++)
1248 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1249 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);
1250 // 2D circle texture
1251 for (y = 0;y < ATTEN2DSIZE;y++)
1252 for (x = 0;x < ATTEN2DSIZE;x++)
1253 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);
1254 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);
1255 // 3D sphere texture
1256 if (r_shadow_texture3d.integer && gl_texture3d)
1258 for (z = 0;z < ATTEN3DSIZE;z++)
1259 for (y = 0;y < ATTEN3DSIZE;y++)
1260 for (x = 0;x < ATTEN3DSIZE;x++)
1261 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));
1262 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);
1265 r_shadow_attenuation3dtexture = NULL;
1268 R_Shadow_MakeTextures_MakeCorona();
1270 // Editor light sprites
1271 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1272 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1273 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1274 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1275 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1276 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1279 void R_Shadow_ValidateCvars(void)
1281 if (r_shadow_texture3d.integer && !gl_texture3d)
1282 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1283 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1284 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1285 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1286 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1289 void R_Shadow_RenderMode_Begin(void)
1293 R_Shadow_ValidateCvars();
1295 if (!r_shadow_attenuation2dtexture
1296 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1297 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1298 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1299 R_Shadow_MakeTextures();
1302 R_Mesh_ColorPointer(NULL, 0, 0);
1303 R_Mesh_ResetTextureState();
1304 GL_BlendFunc(GL_ONE, GL_ZERO);
1305 GL_DepthRange(0, 1);
1306 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1308 GL_DepthMask(false);
1309 GL_Color(0, 0, 0, 1);
1310 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1312 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1314 if (gl_ext_separatestencil.integer)
1316 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1317 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1319 else if (gl_ext_stenciltwoside.integer)
1321 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1322 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1326 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1327 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1330 if (r_glsl.integer && gl_support_fragment_shader)
1331 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1332 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1333 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1335 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1338 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1339 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1340 r_shadow_drawbuffer = drawbuffer;
1341 r_shadow_readbuffer = readbuffer;
1344 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1346 rsurface.rtlight = rtlight;
1349 void R_Shadow_RenderMode_Reset(void)
1352 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1354 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1356 if (gl_support_ext_framebuffer_object)
1358 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1360 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1361 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1362 R_SetViewport(&r_refdef.view.viewport);
1363 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1364 R_Mesh_ColorPointer(NULL, 0, 0);
1365 R_Mesh_ResetTextureState();
1366 GL_DepthRange(0, 1);
1368 GL_DepthMask(false);
1369 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1370 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1371 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1372 qglStencilMask(~0);CHECKGLERROR
1373 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1374 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1375 GL_CullFace(r_refdef.view.cullface_back);
1376 GL_Color(1, 1, 1, 1);
1377 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1378 GL_BlendFunc(GL_ONE, GL_ZERO);
1379 R_SetupGenericShader(false);
1383 void R_Shadow_ClearStencil(void)
1386 GL_Clear(GL_STENCIL_BUFFER_BIT);
1387 r_refdef.stats.lights_clears++;
1390 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1392 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1393 if (r_shadow_rendermode == mode)
1396 R_Shadow_RenderMode_Reset();
1397 GL_ColorMask(0, 0, 0, 0);
1398 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1399 R_SetupDepthOrShadowShader();
1400 qglDepthFunc(GL_LESS);CHECKGLERROR
1401 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1402 r_shadow_rendermode = mode;
1407 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1408 GL_CullFace(GL_NONE);
1409 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1410 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1412 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1413 GL_CullFace(GL_NONE);
1414 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1415 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1417 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1418 GL_CullFace(GL_NONE);
1419 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1420 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1421 qglStencilMask(~0);CHECKGLERROR
1422 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1423 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1424 qglStencilMask(~0);CHECKGLERROR
1425 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1427 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1428 GL_CullFace(GL_NONE);
1429 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1430 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1431 qglStencilMask(~0);CHECKGLERROR
1432 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1433 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1434 qglStencilMask(~0);CHECKGLERROR
1435 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1440 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1444 float nearclip, farclip, bias;
1445 r_viewport_t viewport;
1447 maxsize = r_shadow_shadowmapmaxsize;
1448 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1450 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1451 // complex unrolled cube approach (more flexible)
1452 if (!r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod])
1453 r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod] = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection", size, r_shadow_shadowmapborder);
1454 if (!r_shadow_shadowmaprectangletexture)
1457 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapfilter == 1 || r_shadow_shadowmapfilter == 2);
1458 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1459 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1460 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1464 R_Shadow_RenderMode_Reset();
1465 if (r_shadow_shadowmaprectangletexture)
1467 // render depth into the fbo, do not render color at all
1468 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1469 qglDrawBuffer(GL_NONE);CHECKGLERROR
1470 qglReadBuffer(GL_NONE);CHECKGLERROR
1471 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1472 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1474 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1475 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1477 R_SetupDepthOrShadowShader();
1481 R_SetupShowDepthShader();
1482 qglClearColor(1,1,1,1);CHECKGLERROR
1484 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1485 r_shadow_shadowmap_texturescale[0] = 2*size;
1486 r_shadow_shadowmap_texturescale[1] = 3*size;
1487 r_shadow_shadowmap_texturescale[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1488 r_shadow_shadowmap_texturescale[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1489 // compat for ALU cubemap calcs
1490 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1491 r_shadow_shadowmap_parameters[1] = size;
1492 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmap_texturescale[2];
1493 r_shadow_shadowmap_parameters[3] = r_shadow_shadowmap_texturescale[3];
1494 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1496 R_SetViewport(&viewport);
1497 GL_PolygonOffset(0, 0);
1498 GL_CullFace(GL_NONE); // quake is backwards
1499 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1502 qglClearDepth(1);CHECKGLERROR
1505 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1509 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1512 R_Shadow_RenderMode_Reset();
1513 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1516 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1520 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1521 // only draw light where this geometry was already rendered AND the
1522 // stencil is 128 (values other than this mean shadow)
1523 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1525 r_shadow_rendermode = r_shadow_lightingrendermode;
1526 // do global setup needed for the chosen lighting mode
1527 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1529 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1530 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1534 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1536 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapcubeprojectiontexture[r_shadow_shadowmaplod]));
1540 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1541 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1542 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1546 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1549 R_Shadow_RenderMode_Reset();
1550 GL_BlendFunc(GL_ONE, GL_ONE);
1551 GL_DepthRange(0, 1);
1552 GL_DepthTest(r_showshadowvolumes.integer < 2);
1553 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1554 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1555 GL_CullFace(GL_NONE);
1556 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1559 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1562 R_Shadow_RenderMode_Reset();
1563 GL_BlendFunc(GL_ONE, GL_ONE);
1564 GL_DepthRange(0, 1);
1565 GL_DepthTest(r_showlighting.integer < 2);
1566 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1569 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1573 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1574 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1576 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1579 void R_Shadow_RenderMode_End(void)
1582 R_Shadow_RenderMode_Reset();
1583 R_Shadow_RenderMode_ActiveLight(NULL);
1585 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1586 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1589 int bboxedges[12][2] =
1608 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1610 int i, ix1, iy1, ix2, iy2;
1611 float x1, y1, x2, y2;
1613 float vertex[20][3];
1622 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1623 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1624 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1625 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1627 if (!r_shadow_scissor.integer)
1630 // if view is inside the light box, just say yes it's visible
1631 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1634 x1 = y1 = x2 = y2 = 0;
1636 // transform all corners that are infront of the nearclip plane
1637 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1638 plane4f[3] = r_refdef.view.frustum[4].dist;
1640 for (i = 0;i < 8;i++)
1642 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1643 dist[i] = DotProduct4(corner[i], plane4f);
1644 sign[i] = dist[i] > 0;
1647 VectorCopy(corner[i], vertex[numvertices]);
1651 // if some points are behind the nearclip, add clipped edge points to make
1652 // sure that the scissor boundary is complete
1653 if (numvertices > 0 && numvertices < 8)
1655 // add clipped edge points
1656 for (i = 0;i < 12;i++)
1658 j = bboxedges[i][0];
1659 k = bboxedges[i][1];
1660 if (sign[j] != sign[k])
1662 f = dist[j] / (dist[j] - dist[k]);
1663 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1669 // if we have no points to check, the light is behind the view plane
1673 // if we have some points to transform, check what screen area is covered
1674 x1 = y1 = x2 = y2 = 0;
1676 //Con_Printf("%i vertices to transform...\n", numvertices);
1677 for (i = 0;i < numvertices;i++)
1679 VectorCopy(vertex[i], v);
1680 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1681 //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]);
1684 if (x1 > v2[0]) x1 = v2[0];
1685 if (x2 < v2[0]) x2 = v2[0];
1686 if (y1 > v2[1]) y1 = v2[1];
1687 if (y2 < v2[1]) y2 = v2[1];
1696 // now convert the scissor rectangle to integer screen coordinates
1697 ix1 = (int)(x1 - 1.0f);
1698 iy1 = vid.height - (int)(y2 - 1.0f);
1699 ix2 = (int)(x2 + 1.0f);
1700 iy2 = vid.height - (int)(y1 + 1.0f);
1701 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1703 // clamp it to the screen
1704 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1705 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1706 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1707 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1709 // if it is inside out, it's not visible
1710 if (ix2 <= ix1 || iy2 <= iy1)
1713 // the light area is visible, set up the scissor rectangle
1714 r_shadow_lightscissor[0] = ix1;
1715 r_shadow_lightscissor[1] = iy1;
1716 r_shadow_lightscissor[2] = ix2 - ix1;
1717 r_shadow_lightscissor[3] = iy2 - iy1;
1719 r_refdef.stats.lights_scissored++;
1723 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1725 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1726 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1727 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1728 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1729 if (r_textureunits.integer >= 3)
1731 if (VectorLength2(diffusecolor) > 0)
1733 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1735 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1736 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1737 if ((dot = DotProduct(n, v)) < 0)
1739 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1740 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1743 VectorCopy(ambientcolor, color4f);
1744 if (r_refdef.fogenabled)
1747 f = FogPoint_Model(vertex3f);
1748 VectorScale(color4f, f, color4f);
1755 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1757 VectorCopy(ambientcolor, color4f);
1758 if (r_refdef.fogenabled)
1761 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1762 f = FogPoint_Model(vertex3f);
1763 VectorScale(color4f, f, color4f);
1769 else if (r_textureunits.integer >= 2)
1771 if (VectorLength2(diffusecolor) > 0)
1773 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1775 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1776 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1778 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1779 if ((dot = DotProduct(n, v)) < 0)
1781 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1782 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1783 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1784 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1788 color4f[0] = ambientcolor[0] * distintensity;
1789 color4f[1] = ambientcolor[1] * distintensity;
1790 color4f[2] = ambientcolor[2] * distintensity;
1792 if (r_refdef.fogenabled)
1795 f = FogPoint_Model(vertex3f);
1796 VectorScale(color4f, f, color4f);
1800 VectorClear(color4f);
1806 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1808 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1809 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1811 color4f[0] = ambientcolor[0] * distintensity;
1812 color4f[1] = ambientcolor[1] * distintensity;
1813 color4f[2] = ambientcolor[2] * distintensity;
1814 if (r_refdef.fogenabled)
1817 f = FogPoint_Model(vertex3f);
1818 VectorScale(color4f, f, color4f);
1822 VectorClear(color4f);
1829 if (VectorLength2(diffusecolor) > 0)
1831 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1833 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1834 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1836 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1837 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1838 if ((dot = DotProduct(n, v)) < 0)
1840 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1841 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1842 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1843 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1847 color4f[0] = ambientcolor[0] * distintensity;
1848 color4f[1] = ambientcolor[1] * distintensity;
1849 color4f[2] = ambientcolor[2] * distintensity;
1851 if (r_refdef.fogenabled)
1854 f = FogPoint_Model(vertex3f);
1855 VectorScale(color4f, f, color4f);
1859 VectorClear(color4f);
1865 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1867 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1868 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1870 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1871 color4f[0] = ambientcolor[0] * distintensity;
1872 color4f[1] = ambientcolor[1] * distintensity;
1873 color4f[2] = ambientcolor[2] * distintensity;
1874 if (r_refdef.fogenabled)
1877 f = FogPoint_Model(vertex3f);
1878 VectorScale(color4f, f, color4f);
1882 VectorClear(color4f);
1889 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
1891 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1894 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1895 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1896 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1897 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1898 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1900 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1902 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1903 // the cubemap normalizes this for us
1904 out3f[0] = DotProduct(svector3f, lightdir);
1905 out3f[1] = DotProduct(tvector3f, lightdir);
1906 out3f[2] = DotProduct(normal3f, lightdir);
1910 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
1913 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
1914 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1915 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
1916 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
1917 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
1918 float lightdir[3], eyedir[3], halfdir[3];
1919 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
1921 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
1922 VectorNormalize(lightdir);
1923 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
1924 VectorNormalize(eyedir);
1925 VectorAdd(lightdir, eyedir, halfdir);
1926 // the cubemap normalizes this for us
1927 out3f[0] = DotProduct(svector3f, halfdir);
1928 out3f[1] = DotProduct(tvector3f, halfdir);
1929 out3f[2] = DotProduct(normal3f, halfdir);
1933 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)
1935 // used to display how many times a surface is lit for level design purposes
1936 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1939 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)
1941 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
1942 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
1943 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
1944 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
1946 R_Mesh_ColorPointer(NULL, 0, 0);
1947 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1948 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
1949 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1950 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
1951 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
1952 if (rsurface.texture->backgroundcurrentskinframe)
1954 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
1955 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
1956 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
1957 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
1959 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
1960 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
1961 if(rsurface.texture->colormapping)
1963 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
1964 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1966 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
1967 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
1968 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
1969 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
1970 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
1971 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1973 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1975 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1976 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1978 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1982 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)
1984 // shared final code for all the dot3 layers
1986 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1987 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
1989 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
1990 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
1994 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)
1997 // colorscale accounts for how much we multiply the brightness
2000 // mult is how many times the final pass of the lighting will be
2001 // performed to get more brightness than otherwise possible.
2003 // Limit mult to 64 for sanity sake.
2005 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2007 // 3 3D combine path (Geforce3, Radeon 8500)
2008 memset(&m, 0, sizeof(m));
2009 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2010 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2011 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2012 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2013 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2014 m.tex[1] = R_GetTexture(basetexture);
2015 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2016 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2017 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2018 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2019 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2020 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2021 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2022 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2023 m.texmatrix[2] = rsurface.entitytolight;
2024 GL_BlendFunc(GL_ONE, GL_ONE);
2026 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2028 // 2 3D combine path (Geforce3, original Radeon)
2029 memset(&m, 0, sizeof(m));
2030 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2031 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2032 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2033 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2034 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2035 m.tex[1] = R_GetTexture(basetexture);
2036 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2037 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2038 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2039 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2040 GL_BlendFunc(GL_ONE, GL_ONE);
2042 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2044 // 4 2D combine path (Geforce3, Radeon 8500)
2045 memset(&m, 0, sizeof(m));
2046 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2047 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2048 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2049 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2050 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2051 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2052 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2053 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2054 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2055 m.texmatrix[1] = rsurface.entitytoattenuationz;
2056 m.tex[2] = R_GetTexture(basetexture);
2057 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2058 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2059 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2060 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2061 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2063 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2064 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2065 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2066 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2067 m.texmatrix[3] = rsurface.entitytolight;
2069 GL_BlendFunc(GL_ONE, GL_ONE);
2071 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2073 // 3 2D combine path (Geforce3, original Radeon)
2074 memset(&m, 0, sizeof(m));
2075 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2076 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2077 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2078 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2079 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2080 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2081 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2082 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2083 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2084 m.texmatrix[1] = rsurface.entitytoattenuationz;
2085 m.tex[2] = R_GetTexture(basetexture);
2086 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2087 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2088 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2089 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2090 GL_BlendFunc(GL_ONE, GL_ONE);
2094 // 2/2/2 2D combine path (any dot3 card)
2095 memset(&m, 0, sizeof(m));
2096 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2097 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2098 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2099 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2100 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2101 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2102 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2103 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2104 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2105 m.texmatrix[1] = rsurface.entitytoattenuationz;
2106 R_Mesh_TextureState(&m);
2107 GL_ColorMask(0,0,0,1);
2108 GL_BlendFunc(GL_ONE, GL_ZERO);
2109 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2112 memset(&m, 0, sizeof(m));
2113 m.tex[0] = R_GetTexture(basetexture);
2114 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2115 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2116 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2117 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2118 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2120 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2121 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2122 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2123 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2124 m.texmatrix[1] = rsurface.entitytolight;
2126 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2128 // this final code is shared
2129 R_Mesh_TextureState(&m);
2130 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);
2133 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)
2136 // colorscale accounts for how much we multiply the brightness
2139 // mult is how many times the final pass of the lighting will be
2140 // performed to get more brightness than otherwise possible.
2142 // Limit mult to 64 for sanity sake.
2144 // generate normalization cubemap texcoords
2145 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2146 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2148 // 3/2 3D combine path (Geforce3, Radeon 8500)
2149 memset(&m, 0, sizeof(m));
2150 m.tex[0] = R_GetTexture(normalmaptexture);
2151 m.texcombinergb[0] = GL_REPLACE;
2152 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2153 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2154 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2155 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2156 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2157 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2158 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2159 m.pointer_texcoord_bufferobject[1] = 0;
2160 m.pointer_texcoord_bufferoffset[1] = 0;
2161 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2162 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2163 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2164 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2165 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2166 R_Mesh_TextureState(&m);
2167 GL_ColorMask(0,0,0,1);
2168 GL_BlendFunc(GL_ONE, GL_ZERO);
2169 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2172 memset(&m, 0, sizeof(m));
2173 m.tex[0] = R_GetTexture(basetexture);
2174 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2175 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2176 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2177 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2178 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2180 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2181 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2182 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2183 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2184 m.texmatrix[1] = rsurface.entitytolight;
2186 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2188 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2190 // 1/2/2 3D combine path (original Radeon)
2191 memset(&m, 0, sizeof(m));
2192 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
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 R_Mesh_TextureState(&m);
2198 GL_ColorMask(0,0,0,1);
2199 GL_BlendFunc(GL_ONE, GL_ZERO);
2200 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2203 memset(&m, 0, sizeof(m));
2204 m.tex[0] = R_GetTexture(normalmaptexture);
2205 m.texcombinergb[0] = GL_REPLACE;
2206 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2207 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2208 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2209 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2210 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2211 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2212 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2213 m.pointer_texcoord_bufferobject[1] = 0;
2214 m.pointer_texcoord_bufferoffset[1] = 0;
2215 R_Mesh_TextureState(&m);
2216 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2217 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2220 memset(&m, 0, sizeof(m));
2221 m.tex[0] = R_GetTexture(basetexture);
2222 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2223 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2224 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2225 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2226 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2228 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2229 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2230 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2231 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2232 m.texmatrix[1] = rsurface.entitytolight;
2234 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2236 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2238 // 2/2 3D combine path (original Radeon)
2239 memset(&m, 0, sizeof(m));
2240 m.tex[0] = R_GetTexture(normalmaptexture);
2241 m.texcombinergb[0] = GL_REPLACE;
2242 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2243 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2244 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2245 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2246 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2247 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2248 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2249 m.pointer_texcoord_bufferobject[1] = 0;
2250 m.pointer_texcoord_bufferoffset[1] = 0;
2251 R_Mesh_TextureState(&m);
2252 GL_ColorMask(0,0,0,1);
2253 GL_BlendFunc(GL_ONE, GL_ZERO);
2254 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2257 memset(&m, 0, sizeof(m));
2258 m.tex[0] = R_GetTexture(basetexture);
2259 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2260 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2261 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2262 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2263 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2264 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2265 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2266 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2267 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2268 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2270 else if (r_textureunits.integer >= 4)
2272 // 4/2 2D combine path (Geforce3, Radeon 8500)
2273 memset(&m, 0, sizeof(m));
2274 m.tex[0] = R_GetTexture(normalmaptexture);
2275 m.texcombinergb[0] = GL_REPLACE;
2276 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2277 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2278 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2279 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2280 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2281 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2282 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2283 m.pointer_texcoord_bufferobject[1] = 0;
2284 m.pointer_texcoord_bufferoffset[1] = 0;
2285 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2286 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2287 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2288 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2289 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2290 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2291 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2292 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2293 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2294 m.texmatrix[3] = rsurface.entitytoattenuationz;
2295 R_Mesh_TextureState(&m);
2296 GL_ColorMask(0,0,0,1);
2297 GL_BlendFunc(GL_ONE, GL_ZERO);
2298 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2301 memset(&m, 0, sizeof(m));
2302 m.tex[0] = R_GetTexture(basetexture);
2303 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2304 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2305 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2306 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2307 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2309 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2310 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2311 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2312 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2313 m.texmatrix[1] = rsurface.entitytolight;
2315 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2319 // 2/2/2 2D combine path (any dot3 card)
2320 memset(&m, 0, sizeof(m));
2321 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2322 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2323 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2324 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2325 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2326 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2327 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2328 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2329 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2330 m.texmatrix[1] = rsurface.entitytoattenuationz;
2331 R_Mesh_TextureState(&m);
2332 GL_ColorMask(0,0,0,1);
2333 GL_BlendFunc(GL_ONE, GL_ZERO);
2334 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2337 memset(&m, 0, sizeof(m));
2338 m.tex[0] = R_GetTexture(normalmaptexture);
2339 m.texcombinergb[0] = GL_REPLACE;
2340 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2341 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2342 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2343 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2344 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2345 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2346 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2347 m.pointer_texcoord_bufferobject[1] = 0;
2348 m.pointer_texcoord_bufferoffset[1] = 0;
2349 R_Mesh_TextureState(&m);
2350 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2351 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2354 memset(&m, 0, sizeof(m));
2355 m.tex[0] = R_GetTexture(basetexture);
2356 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2357 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2358 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2359 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2360 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2362 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2363 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2364 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2365 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2366 m.texmatrix[1] = rsurface.entitytolight;
2368 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2370 // this final code is shared
2371 R_Mesh_TextureState(&m);
2372 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);
2375 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)
2377 float glossexponent;
2379 // FIXME: detect blendsquare!
2380 //if (!gl_support_blendsquare)
2383 // generate normalization cubemap texcoords
2384 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2385 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2387 // 2/0/0/1/2 3D combine blendsquare path
2388 memset(&m, 0, sizeof(m));
2389 m.tex[0] = R_GetTexture(normalmaptexture);
2390 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2391 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2392 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2393 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2394 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2395 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2396 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2397 m.pointer_texcoord_bufferobject[1] = 0;
2398 m.pointer_texcoord_bufferoffset[1] = 0;
2399 R_Mesh_TextureState(&m);
2400 GL_ColorMask(0,0,0,1);
2401 // this squares the result
2402 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2403 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2405 // second and third pass
2406 R_Mesh_ResetTextureState();
2407 // square alpha in framebuffer a few times to make it shiny
2408 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2409 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2410 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2413 memset(&m, 0, sizeof(m));
2414 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2415 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2416 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2417 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2418 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2419 R_Mesh_TextureState(&m);
2420 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2421 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2424 memset(&m, 0, sizeof(m));
2425 m.tex[0] = R_GetTexture(glosstexture);
2426 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2427 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2428 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2429 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2430 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2432 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2433 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2434 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2435 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2436 m.texmatrix[1] = rsurface.entitytolight;
2438 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2440 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2442 // 2/0/0/2 3D combine blendsquare path
2443 memset(&m, 0, sizeof(m));
2444 m.tex[0] = R_GetTexture(normalmaptexture);
2445 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2446 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2447 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2448 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2449 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2450 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2451 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2452 m.pointer_texcoord_bufferobject[1] = 0;
2453 m.pointer_texcoord_bufferoffset[1] = 0;
2454 R_Mesh_TextureState(&m);
2455 GL_ColorMask(0,0,0,1);
2456 // this squares the result
2457 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2458 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2460 // second and third pass
2461 R_Mesh_ResetTextureState();
2462 // square alpha in framebuffer a few times to make it shiny
2463 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2464 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2465 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2468 memset(&m, 0, sizeof(m));
2469 m.tex[0] = R_GetTexture(glosstexture);
2470 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2471 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2472 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2473 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2474 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2475 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2476 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2477 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2478 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2479 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2483 // 2/0/0/2/2 2D combine blendsquare path
2484 memset(&m, 0, sizeof(m));
2485 m.tex[0] = R_GetTexture(normalmaptexture);
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_ColorMask(0,0,0,1);
2497 // this squares the result
2498 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2499 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2501 // second and third pass
2502 R_Mesh_ResetTextureState();
2503 // square alpha in framebuffer a few times to make it shiny
2504 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2505 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2506 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2509 memset(&m, 0, sizeof(m));
2510 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2511 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2512 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2513 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2514 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2515 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2516 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2517 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2518 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2519 m.texmatrix[1] = rsurface.entitytoattenuationz;
2520 R_Mesh_TextureState(&m);
2521 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2522 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2525 memset(&m, 0, sizeof(m));
2526 m.tex[0] = R_GetTexture(glosstexture);
2527 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2528 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2529 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2530 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2531 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2533 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2534 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2535 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2536 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2537 m.texmatrix[1] = rsurface.entitytolight;
2539 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2541 // this final code is shared
2542 R_Mesh_TextureState(&m);
2543 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);
2546 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)
2548 // ARB path (any Geforce, any Radeon)
2549 qboolean doambient = ambientscale > 0;
2550 qboolean dodiffuse = diffusescale > 0;
2551 qboolean dospecular = specularscale > 0;
2552 if (!doambient && !dodiffuse && !dospecular)
2554 R_Mesh_ColorPointer(NULL, 0, 0);
2556 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2558 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2562 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2564 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2569 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2571 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2574 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2577 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2584 int newnumtriangles;
2588 int maxtriangles = 4096;
2589 int newelements[4096*3];
2590 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2591 for (renders = 0;renders < 64;renders++)
2596 newnumtriangles = 0;
2598 // due to low fillrate on the cards this vertex lighting path is
2599 // designed for, we manually cull all triangles that do not
2600 // contain a lit vertex
2601 // this builds batches of triangles from multiple surfaces and
2602 // renders them at once
2603 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2605 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2607 if (newnumtriangles)
2609 newfirstvertex = min(newfirstvertex, e[0]);
2610 newlastvertex = max(newlastvertex, e[0]);
2614 newfirstvertex = e[0];
2615 newlastvertex = e[0];
2617 newfirstvertex = min(newfirstvertex, e[1]);
2618 newlastvertex = max(newlastvertex, e[1]);
2619 newfirstvertex = min(newfirstvertex, e[2]);
2620 newlastvertex = max(newlastvertex, e[2]);
2626 if (newnumtriangles >= maxtriangles)
2628 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2629 newnumtriangles = 0;
2635 if (newnumtriangles >= 1)
2637 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2640 // if we couldn't find any lit triangles, exit early
2643 // now reduce the intensity for the next overbright pass
2644 // we have to clamp to 0 here incase the drivers have improper
2645 // handling of negative colors
2646 // (some old drivers even have improper handling of >1 color)
2648 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2650 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2652 c[0] = max(0, c[0] - 1);
2653 c[1] = max(0, c[1] - 1);
2654 c[2] = max(0, c[2] - 1);
2666 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)
2668 // OpenGL 1.1 path (anything)
2669 float ambientcolorbase[3], diffusecolorbase[3];
2670 float ambientcolorpants[3], diffusecolorpants[3];
2671 float ambientcolorshirt[3], diffusecolorshirt[3];
2673 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2674 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2675 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2676 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2677 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2678 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2679 memset(&m, 0, sizeof(m));
2680 m.tex[0] = R_GetTexture(basetexture);
2681 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2682 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2683 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2684 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2685 if (r_textureunits.integer >= 2)
2688 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2689 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2690 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2691 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2692 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2693 if (r_textureunits.integer >= 3)
2695 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2696 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2697 m.texmatrix[2] = rsurface.entitytoattenuationz;
2698 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2699 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2700 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2703 R_Mesh_TextureState(&m);
2704 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2705 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2708 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2709 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2713 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2714 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2718 extern cvar_t gl_lightmaps;
2719 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)
2721 float ambientscale, diffusescale, specularscale;
2722 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2724 // calculate colors to render this texture with
2725 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2726 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2727 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2728 ambientscale = rsurface.rtlight->ambientscale;
2729 diffusescale = rsurface.rtlight->diffusescale;
2730 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2731 if (!r_shadow_usenormalmap.integer)
2733 ambientscale += 1.0f * diffusescale;
2737 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2739 RSurf_SetupDepthAndCulling();
2740 nmap = rsurface.texture->currentskinframe->nmap;
2741 if (gl_lightmaps.integer)
2742 nmap = r_texture_blanknormalmap;
2743 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2745 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2746 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2749 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2750 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2751 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2754 VectorClear(lightcolorpants);
2757 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2758 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2759 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2762 VectorClear(lightcolorshirt);
2763 switch (r_shadow_rendermode)
2765 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2766 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2767 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);
2769 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2770 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);
2772 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2773 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);
2775 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2776 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);
2779 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2785 switch (r_shadow_rendermode)
2787 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2788 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2789 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);
2791 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2792 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);
2794 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2795 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);
2797 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2798 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);
2801 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2807 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)
2809 matrix4x4_t tempmatrix = *matrix;
2810 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2812 // if this light has been compiled before, free the associated data
2813 R_RTLight_Uncompile(rtlight);
2815 // clear it completely to avoid any lingering data
2816 memset(rtlight, 0, sizeof(*rtlight));
2818 // copy the properties
2819 rtlight->matrix_lighttoworld = tempmatrix;
2820 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2821 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2822 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2823 VectorCopy(color, rtlight->color);
2824 rtlight->cubemapname[0] = 0;
2825 if (cubemapname && cubemapname[0])
2826 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2827 rtlight->shadow = shadow;
2828 rtlight->corona = corona;
2829 rtlight->style = style;
2830 rtlight->isstatic = isstatic;
2831 rtlight->coronasizescale = coronasizescale;
2832 rtlight->ambientscale = ambientscale;
2833 rtlight->diffusescale = diffusescale;
2834 rtlight->specularscale = specularscale;
2835 rtlight->flags = flags;
2837 // compute derived data
2838 //rtlight->cullradius = rtlight->radius;
2839 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2840 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2841 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2842 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2843 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2844 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2845 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2848 // compiles rtlight geometry
2849 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2850 void R_RTLight_Compile(rtlight_t *rtlight)
2853 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2854 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2855 entity_render_t *ent = r_refdef.scene.worldentity;
2856 dp_model_t *model = r_refdef.scene.worldmodel;
2857 unsigned char *data;
2860 // compile the light
2861 rtlight->compiled = true;
2862 rtlight->static_numleafs = 0;
2863 rtlight->static_numleafpvsbytes = 0;
2864 rtlight->static_leaflist = NULL;
2865 rtlight->static_leafpvs = NULL;
2866 rtlight->static_numsurfaces = 0;
2867 rtlight->static_surfacelist = NULL;
2868 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2869 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2870 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2871 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2872 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2873 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2875 if (model && model->GetLightInfo)
2877 // this variable must be set for the CompileShadowVolume code
2878 r_shadow_compilingrtlight = rtlight;
2879 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);
2880 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);
2881 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2882 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2883 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2884 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2885 rtlight->static_numsurfaces = numsurfaces;
2886 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2887 rtlight->static_numleafs = numleafs;
2888 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2889 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2890 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2891 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2892 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2893 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2894 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2895 if (rtlight->static_numsurfaces)
2896 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2897 if (rtlight->static_numleafs)
2898 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2899 if (rtlight->static_numleafpvsbytes)
2900 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2901 if (rtlight->static_numshadowtrispvsbytes)
2902 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2903 if (rtlight->static_numlighttrispvsbytes)
2904 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2905 if (model->CompileShadowVolume && rtlight->shadow)
2906 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2907 // now we're done compiling the rtlight
2908 r_shadow_compilingrtlight = NULL;
2912 // use smallest available cullradius - box radius or light radius
2913 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2914 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2916 shadowzpasstris = 0;
2917 if (rtlight->static_meshchain_shadow_zpass)
2918 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2919 shadowzpasstris += mesh->numtriangles;
2921 shadowzfailtris = 0;
2922 if (rtlight->static_meshchain_shadow_zfail)
2923 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2924 shadowzfailtris += mesh->numtriangles;
2927 if (rtlight->static_numlighttrispvsbytes)
2928 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2929 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2933 if (rtlight->static_numlighttrispvsbytes)
2934 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2935 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2938 if (developer.integer >= 10)
2939 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);
2942 void R_RTLight_Uncompile(rtlight_t *rtlight)
2944 if (rtlight->compiled)
2946 if (rtlight->static_meshchain_shadow_zpass)
2947 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2948 rtlight->static_meshchain_shadow_zpass = NULL;
2949 if (rtlight->static_meshchain_shadow_zfail)
2950 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2951 rtlight->static_meshchain_shadow_zfail = NULL;
2952 // these allocations are grouped
2953 if (rtlight->static_surfacelist)
2954 Mem_Free(rtlight->static_surfacelist);
2955 rtlight->static_numleafs = 0;
2956 rtlight->static_numleafpvsbytes = 0;
2957 rtlight->static_leaflist = NULL;
2958 rtlight->static_leafpvs = NULL;
2959 rtlight->static_numsurfaces = 0;
2960 rtlight->static_surfacelist = NULL;
2961 rtlight->static_numshadowtrispvsbytes = 0;
2962 rtlight->static_shadowtrispvs = NULL;
2963 rtlight->static_numlighttrispvsbytes = 0;
2964 rtlight->static_lighttrispvs = NULL;
2965 rtlight->compiled = false;
2969 void R_Shadow_UncompileWorldLights(void)
2973 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2974 for (lightindex = 0;lightindex < range;lightindex++)
2976 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2979 R_RTLight_Uncompile(&light->rtlight);
2983 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2987 // reset the count of frustum planes
2988 // see rsurface.rtlight_frustumplanes definition for how much this array
2990 rsurface.rtlight_numfrustumplanes = 0;
2992 // haven't implemented a culling path for ortho rendering
2993 if (!r_refdef.view.useperspective)
2995 // check if the light is on screen and copy the 4 planes if it is
2996 for (i = 0;i < 4;i++)
2997 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3000 for (i = 0;i < 4;i++)
3001 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3006 // generate a deformed frustum that includes the light origin, this is
3007 // used to cull shadow casting surfaces that can not possibly cast a
3008 // shadow onto the visible light-receiving surfaces, which can be a
3011 // if the light origin is onscreen the result will be 4 planes exactly
3012 // if the light origin is offscreen on only one axis the result will
3013 // be exactly 5 planes (split-side case)
3014 // if the light origin is offscreen on two axes the result will be
3015 // exactly 4 planes (stretched corner case)
3016 for (i = 0;i < 4;i++)
3018 // quickly reject standard frustum planes that put the light
3019 // origin outside the frustum
3020 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3023 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3025 // if all the standard frustum planes were accepted, the light is onscreen
3026 // otherwise we need to generate some more planes below...
3027 if (rsurface.rtlight_numfrustumplanes < 4)
3029 // at least one of the stock frustum planes failed, so we need to
3030 // create one or two custom planes to enclose the light origin
3031 for (i = 0;i < 4;i++)
3033 // create a plane using the view origin and light origin, and a
3034 // single point from the frustum corner set
3035 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3036 VectorNormalize(plane.normal);
3037 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3038 // see if this plane is backwards and flip it if so
3039 for (j = 0;j < 4;j++)
3040 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3044 VectorNegate(plane.normal, plane.normal);
3046 // flipped plane, test again to see if it is now valid
3047 for (j = 0;j < 4;j++)
3048 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3050 // if the plane is still not valid, then it is dividing the
3051 // frustum and has to be rejected
3055 // we have created a valid plane, compute extra info
3056 PlaneClassify(&plane);
3058 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3060 // if we've found 5 frustum planes then we have constructed a
3061 // proper split-side case and do not need to keep searching for
3062 // planes to enclose the light origin
3063 if (rsurface.rtlight_numfrustumplanes == 5)
3071 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3073 plane = rsurface.rtlight_frustumplanes[i];
3074 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));
3079 // now add the light-space box planes if the light box is rotated, as any
3080 // caster outside the oriented light box is irrelevant (even if it passed
3081 // the worldspace light box, which is axial)
3082 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3084 for (i = 0;i < 6;i++)
3088 v[i >> 1] = (i & 1) ? -1 : 1;
3089 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3090 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3091 plane.dist = VectorNormalizeLength(plane.normal);
3092 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3093 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3099 // add the world-space reduced box planes
3100 for (i = 0;i < 6;i++)
3102 VectorClear(plane.normal);
3103 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3104 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3105 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3114 // reduce all plane distances to tightly fit the rtlight cull box, which
3116 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3117 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3118 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3119 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3120 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3121 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3122 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3123 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3124 oldnum = rsurface.rtlight_numfrustumplanes;
3125 rsurface.rtlight_numfrustumplanes = 0;
3126 for (j = 0;j < oldnum;j++)
3128 // find the nearest point on the box to this plane
3129 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3130 for (i = 1;i < 8;i++)
3132 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3133 if (bestdist > dist)
3136 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);
3137 // if the nearest point is near or behind the plane, we want this
3138 // plane, otherwise the plane is useless as it won't cull anything
3139 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3141 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3142 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3149 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3154 int surfacelistindex;
3155 msurface_t *surface;
3157 RSurf_ActiveWorldEntity();
3158 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3160 if (r_refdef.scene.worldentity->model)
3161 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3162 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3166 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3169 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3170 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3171 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3172 for (;mesh;mesh = mesh->next)
3174 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3175 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3176 GL_LockArrays(0, mesh->numverts);
3177 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3179 // increment stencil if frontface is infront of depthbuffer
3180 GL_CullFace(r_refdef.view.cullface_back);
3181 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3182 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3183 // decrement stencil if backface is infront of depthbuffer
3184 GL_CullFace(r_refdef.view.cullface_front);
3185 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3187 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3189 // decrement stencil if backface is behind depthbuffer
3190 GL_CullFace(r_refdef.view.cullface_front);
3191 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3192 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3193 // increment stencil if frontface is behind depthbuffer
3194 GL_CullFace(r_refdef.view.cullface_back);
3195 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3197 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3198 GL_LockArrays(0, 0);
3202 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3204 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3205 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3207 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3208 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3209 if (CHECKPVSBIT(trispvs, t))
3210 shadowmarklist[numshadowmark++] = t;
3212 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);
3214 else if (numsurfaces)
3215 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3217 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3220 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3222 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3223 vec_t relativeshadowradius;
3224 RSurf_ActiveModelEntity(ent, false, false);
3225 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3226 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3227 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3228 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3229 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3230 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3231 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3232 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3233 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3234 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3236 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3237 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3240 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3242 // set up properties for rendering light onto this entity
3243 RSurf_ActiveModelEntity(ent, true, true);
3244 GL_AlphaTest(false);
3245 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3246 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3247 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3248 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3249 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3250 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3253 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3255 if (!r_refdef.scene.worldmodel->DrawLight)
3258 // set up properties for rendering light onto this entity
3259 RSurf_ActiveWorldEntity();
3260 GL_AlphaTest(false);
3261 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3262 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3263 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3264 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3265 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3266 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3268 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3270 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3273 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3275 dp_model_t *model = ent->model;
3276 if (!model->DrawLight)
3279 R_Shadow_SetupEntityLight(ent);
3281 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3283 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3287 {{ 0, 0, 0}, "px", true, true, true},
3288 {{ 0, 90, 0}, "py", false, true, false},
3289 {{ 0, 180, 0}, "nx", false, false, true},
3290 {{ 0, 270, 0}, "ny", true, false, false},
3291 {{-90, 180, 0}, "pz", false, false, true},
3292 {{ 90, 180, 0}, "nz", false, false, true}
3295 static const double shadowviewmat16[6][4][4] =
3335 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3339 int numleafs, numsurfaces;
3340 int *leaflist, *surfacelist;
3341 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3342 int numlightentities;
3343 int numlightentities_noselfshadow;
3344 int numshadowentities;
3345 int numshadowentities_noselfshadow;
3346 static entity_render_t *lightentities[MAX_EDICTS];
3347 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3348 static entity_render_t *shadowentities[MAX_EDICTS];
3349 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3350 vec3_t nearestpoint;
3352 qboolean castshadows;
3355 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3356 // skip lights that are basically invisible (color 0 0 0)
3357 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3360 // loading is done before visibility checks because loading should happen
3361 // all at once at the start of a level, not when it stalls gameplay.
3362 // (especially important to benchmarks)
3364 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3365 R_RTLight_Compile(rtlight);
3367 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3369 // look up the light style value at this time
3370 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3371 VectorScale(rtlight->color, f, rtlight->currentcolor);
3373 if (rtlight->selected)
3375 f = 2 + sin(realtime * M_PI * 4.0);
3376 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3380 // if lightstyle is currently off, don't draw the light
3381 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3384 // if the light box is offscreen, skip it
3385 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3388 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3389 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3391 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3393 // compiled light, world available and can receive realtime lighting
3394 // retrieve leaf information
3395 numleafs = rtlight->static_numleafs;
3396 leaflist = rtlight->static_leaflist;
3397 leafpvs = rtlight->static_leafpvs;
3398 numsurfaces = rtlight->static_numsurfaces;
3399 surfacelist = rtlight->static_surfacelist;
3400 shadowtrispvs = rtlight->static_shadowtrispvs;
3401 lighttrispvs = rtlight->static_lighttrispvs;
3403 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3405 // dynamic light, world available and can receive realtime lighting
3406 // calculate lit surfaces and leafs
3407 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);
3408 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);
3409 leaflist = r_shadow_buffer_leaflist;
3410 leafpvs = r_shadow_buffer_leafpvs;
3411 surfacelist = r_shadow_buffer_surfacelist;
3412 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3413 lighttrispvs = r_shadow_buffer_lighttrispvs;
3414 // if the reduced leaf bounds are offscreen, skip it
3415 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3426 shadowtrispvs = NULL;
3427 lighttrispvs = NULL;
3429 // check if light is illuminating any visible leafs
3432 for (i = 0;i < numleafs;i++)
3433 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3438 // set up a scissor rectangle for this light
3439 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3442 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3444 // make a list of lit entities and shadow casting entities
3445 numlightentities = 0;
3446 numlightentities_noselfshadow = 0;
3447 numshadowentities = 0;
3448 numshadowentities_noselfshadow = 0;
3449 // add dynamic entities that are lit by the light
3450 if (r_drawentities.integer)
3452 for (i = 0;i < r_refdef.scene.numentities;i++)
3455 entity_render_t *ent = r_refdef.scene.entities[i];
3457 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3459 // skip the object entirely if it is not within the valid
3460 // shadow-casting region (which includes the lit region)
3461 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3463 if (!(model = ent->model))
3465 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3467 // this entity wants to receive light, is visible, and is
3468 // inside the light box
3469 // TODO: check if the surfaces in the model can receive light
3470 // so now check if it's in a leaf seen by the light
3471 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))
3473 if (ent->flags & RENDER_NOSELFSHADOW)
3474 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3476 lightentities[numlightentities++] = ent;
3477 // since it is lit, it probably also casts a shadow...
3478 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3479 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3480 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3482 // note: exterior models without the RENDER_NOSELFSHADOW
3483 // flag still create a RENDER_NOSELFSHADOW shadow but
3484 // are lit normally, this means that they are
3485 // self-shadowing but do not shadow other
3486 // RENDER_NOSELFSHADOW entities such as the gun
3487 // (very weird, but keeps the player shadow off the gun)
3488 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3489 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3491 shadowentities[numshadowentities++] = ent;
3494 else if (ent->flags & RENDER_SHADOW)
3496 // this entity is not receiving light, but may still need to
3498 // TODO: check if the surfaces in the model can cast shadow
3499 // now check if it is in a leaf seen by the light
3500 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))
3502 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3503 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3504 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3506 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3507 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3509 shadowentities[numshadowentities++] = ent;
3515 // return if there's nothing at all to light
3516 if (!numlightentities && !numsurfaces)
3519 // don't let sound skip if going slow
3520 if (r_refdef.scene.extraupdate)
3523 // make this the active rtlight for rendering purposes
3524 R_Shadow_RenderMode_ActiveLight(rtlight);
3525 // count this light in the r_speeds
3526 r_refdef.stats.lights++;
3528 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3530 // optionally draw visible shape of the shadow volumes
3531 // for performance analysis by level designers
3532 R_Shadow_RenderMode_VisibleShadowVolumes();
3534 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3535 for (i = 0;i < numshadowentities;i++)
3536 R_Shadow_DrawEntityShadow(shadowentities[i]);
3537 for (i = 0;i < numshadowentities_noselfshadow;i++)
3538 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3541 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3543 // optionally draw the illuminated areas
3544 // for performance analysis by level designers
3545 R_Shadow_RenderMode_VisibleLighting(false, false);
3547 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3548 for (i = 0;i < numlightentities;i++)
3549 R_Shadow_DrawEntityLight(lightentities[i]);
3550 for (i = 0;i < numlightentities_noselfshadow;i++)
3551 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3554 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3556 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3557 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3558 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3559 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3560 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3561 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3563 if (castshadows && r_shadow_shadowmode && r_glsl.integer && gl_support_fragment_shader)
3568 r_shadow_shadowmaplod = 0;
3569 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3570 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3571 r_shadow_shadowmaplod = i;
3573 size = bound(1, r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod, 2048);
3575 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3577 // render shadow casters into 6 sided depth texture
3578 for (side = 0;side < 6;side++)
3580 R_Shadow_RenderMode_ShadowMap(side, true, size);
3582 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3583 for (i = 0;i < numshadowentities;i++)
3584 R_Shadow_DrawEntityShadow(shadowentities[i]);
3587 if (numlightentities_noselfshadow)
3589 // render lighting using the depth texture as shadowmap
3590 // draw lighting in the unmasked areas
3591 R_Shadow_RenderMode_Lighting(false, false, true);
3592 for (i = 0;i < numlightentities_noselfshadow;i++)
3593 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3596 // render shadow casters into 6 sided depth texture
3597 for (side = 0;side < 6;side++)
3599 R_Shadow_RenderMode_ShadowMap(side, false, size);
3600 for (i = 0;i < numshadowentities_noselfshadow;i++)
3601 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3604 // render lighting using the depth texture as shadowmap
3605 // draw lighting in the unmasked areas
3606 R_Shadow_RenderMode_Lighting(false, false, true);
3607 // draw lighting in the unmasked areas
3609 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3610 for (i = 0;i < numlightentities;i++)
3611 R_Shadow_DrawEntityLight(lightentities[i]);
3613 else if (castshadows && gl_stencil)
3615 // draw stencil shadow volumes to mask off pixels that are in shadow
3616 // so that they won't receive lighting
3617 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3618 R_Shadow_ClearStencil();
3620 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3621 for (i = 0;i < numshadowentities;i++)
3622 R_Shadow_DrawEntityShadow(shadowentities[i]);
3623 if (numlightentities_noselfshadow)
3625 // draw lighting in the unmasked areas
3626 R_Shadow_RenderMode_Lighting(true, false, false);
3627 for (i = 0;i < numlightentities_noselfshadow;i++)
3628 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3630 // optionally draw the illuminated areas
3631 // for performance analysis by level designers
3632 if (r_showlighting.integer && r_refdef.view.showdebug)
3634 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3635 for (i = 0;i < numlightentities_noselfshadow;i++)
3636 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3639 for (i = 0;i < numshadowentities_noselfshadow;i++)
3640 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3642 if (numsurfaces + numlightentities)
3644 // draw lighting in the unmasked areas
3645 R_Shadow_RenderMode_Lighting(true, false, false);
3647 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3648 for (i = 0;i < numlightentities;i++)
3649 R_Shadow_DrawEntityLight(lightentities[i]);
3654 if (numsurfaces + numlightentities)
3656 // draw lighting in the unmasked areas
3657 R_Shadow_RenderMode_Lighting(false, false, false);
3659 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3660 for (i = 0;i < numlightentities;i++)
3661 R_Shadow_DrawEntityLight(lightentities[i]);
3662 for (i = 0;i < numlightentities_noselfshadow;i++)
3663 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3668 void R_Shadow_DrawLightSprites(void);
3669 void R_ShadowVolumeLighting(qboolean visible)
3677 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer || r_shadow_shadowmapfilter != r_shadow_shadowmapping_filterquality.integer || r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3678 R_Shadow_FreeShadowMaps();
3680 if (r_editlights.integer)
3681 R_Shadow_DrawLightSprites();
3683 R_Shadow_RenderMode_Begin();
3685 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3686 if (r_shadow_debuglight.integer >= 0)
3688 lightindex = r_shadow_debuglight.integer;
3689 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3690 if (light && (light->flags & flag))
3691 R_DrawRTLight(&light->rtlight, visible);
3695 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3696 for (lightindex = 0;lightindex < range;lightindex++)
3698 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3699 if (light && (light->flags & flag))
3700 R_DrawRTLight(&light->rtlight, visible);
3703 if (r_refdef.scene.rtdlight)
3704 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3705 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3707 R_Shadow_RenderMode_End();
3710 extern const float r_screenvertex3f[12];
3711 extern void R_SetupView(qboolean allowwaterclippingplane);
3712 extern void R_ResetViewRendering3D(void);
3713 extern void R_ResetViewRendering2D(void);
3714 extern cvar_t r_shadows;
3715 extern cvar_t r_shadows_darken;
3716 extern cvar_t r_shadows_drawafterrtlighting;
3717 extern cvar_t r_shadows_castfrombmodels;
3718 extern cvar_t r_shadows_throwdistance;
3719 extern cvar_t r_shadows_throwdirection;
3720 void R_DrawModelShadows(void)
3723 float relativethrowdistance;
3724 entity_render_t *ent;
3725 vec3_t relativelightorigin;
3726 vec3_t relativelightdirection;
3727 vec3_t relativeshadowmins, relativeshadowmaxs;
3728 vec3_t tmp, shadowdir;
3730 if (!r_drawentities.integer || !gl_stencil)
3734 R_ResetViewRendering3D();
3735 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3736 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3737 R_Shadow_RenderMode_Begin();
3738 R_Shadow_RenderMode_ActiveLight(NULL);
3739 r_shadow_lightscissor[0] = r_refdef.view.x;
3740 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3741 r_shadow_lightscissor[2] = r_refdef.view.width;
3742 r_shadow_lightscissor[3] = r_refdef.view.height;
3743 R_Shadow_RenderMode_StencilShadowVolumes(false);
3746 if (r_shadows.integer == 2)
3748 Math_atov(r_shadows_throwdirection.string, shadowdir);
3749 VectorNormalize(shadowdir);
3752 R_Shadow_ClearStencil();
3754 for (i = 0;i < r_refdef.scene.numentities;i++)
3756 ent = r_refdef.scene.entities[i];
3758 // cast shadows from anything of the map (submodels are optional)
3759 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3761 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3762 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3763 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3764 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3765 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3768 if(ent->entitynumber != 0)
3770 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3771 int entnum, entnum2, recursion;
3772 entnum = entnum2 = ent->entitynumber;
3773 for(recursion = 32; recursion > 0; --recursion)
3775 entnum2 = cl.entities[entnum].state_current.tagentity;
3776 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3781 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3783 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3784 // transform into modelspace of OUR entity
3785 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3786 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3789 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3792 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3795 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3796 RSurf_ActiveModelEntity(ent, false, false);
3797 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3798 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3802 // not really the right mode, but this will disable any silly stencil features
3803 R_Shadow_RenderMode_End();
3805 // set up ortho view for rendering this pass
3806 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3807 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3808 //GL_ScissorTest(true);
3809 //R_Mesh_Matrix(&identitymatrix);
3810 //R_Mesh_ResetTextureState();
3811 R_ResetViewRendering2D();
3812 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3813 R_Mesh_ColorPointer(NULL, 0, 0);
3814 R_SetupGenericShader(false);
3816 // set up a darkening blend on shadowed areas
3817 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3818 //GL_DepthRange(0, 1);
3819 //GL_DepthTest(false);
3820 //GL_DepthMask(false);
3821 //GL_PolygonOffset(0, 0);CHECKGLERROR
3822 GL_Color(0, 0, 0, r_shadows_darken.value);
3823 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3824 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3825 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3826 qglStencilMask(~0);CHECKGLERROR
3827 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3828 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3830 // apply the blend to the shadowed areas
3831 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3833 // restore the viewport
3834 R_SetViewport(&r_refdef.view.viewport);
3836 // restore other state to normal
3837 //R_Shadow_RenderMode_End();
3840 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3843 vec3_t centerorigin;
3844 // if it's too close, skip it
3845 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3847 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3850 if (usequery && r_numqueries + 2 <= r_maxqueries)
3852 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3853 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3854 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
3857 // 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
3858 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
3859 qglDepthFunc(GL_ALWAYS);
3860 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);
3861 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3862 qglDepthFunc(GL_LEQUAL);
3863 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
3864 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);
3865 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
3868 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
3871 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
3874 GLint allpixels = 0, visiblepixels = 0;
3875 // now we have to check the query result
3876 if (rtlight->corona_queryindex_visiblepixels)
3879 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
3880 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
3882 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
3883 if (visiblepixels < 1 || allpixels < 1)
3885 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
3886 cscale *= rtlight->corona_visibility;
3890 // FIXME: these traces should scan all render entities instead of cl.world
3891 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
3894 VectorScale(rtlight->color, cscale, color);
3895 if (VectorLength(color) > (1.0f / 256.0f))
3896 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);
3899 void R_DrawCoronas(void)
3907 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
3909 if (r_waterstate.renderingscene)
3911 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3912 R_Mesh_Matrix(&identitymatrix);
3914 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3916 // check occlusion of coronas
3917 // use GL_ARB_occlusion_query if available
3918 // otherwise use raytraces
3920 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
3923 GL_ColorMask(0,0,0,0);
3924 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
3925 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
3928 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
3929 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
3931 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
3935 for (lightindex = 0;lightindex < range;lightindex++)
3937 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3940 rtlight = &light->rtlight;
3941 rtlight->corona_visibility = 0;
3942 rtlight->corona_queryindex_visiblepixels = 0;
3943 rtlight->corona_queryindex_allpixels = 0;
3944 if (!(rtlight->flags & flag))
3946 if (rtlight->corona <= 0)
3948 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
3950 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3952 for (i = 0;i < r_refdef.scene.numlights;i++)
3954 rtlight = r_refdef.scene.lights[i];
3955 rtlight->corona_visibility = 0;
3956 rtlight->corona_queryindex_visiblepixels = 0;
3957 rtlight->corona_queryindex_allpixels = 0;
3958 if (!(rtlight->flags & flag))
3960 if (rtlight->corona <= 0)
3962 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
3965 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3967 // now draw the coronas using the query data for intensity info
3968 for (lightindex = 0;lightindex < range;lightindex++)
3970 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3973 rtlight = &light->rtlight;
3974 if (rtlight->corona_visibility <= 0)
3976 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3978 for (i = 0;i < r_refdef.scene.numlights;i++)
3980 rtlight = r_refdef.scene.lights[i];
3981 if (rtlight->corona_visibility <= 0)
3983 if (gl_flashblend.integer)
3984 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
3986 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
3992 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
3993 typedef struct suffixinfo_s
3996 qboolean flipx, flipy, flipdiagonal;
3999 static suffixinfo_t suffix[3][6] =
4002 {"px", false, false, false},
4003 {"nx", false, false, false},
4004 {"py", false, false, false},
4005 {"ny", false, false, false},
4006 {"pz", false, false, false},
4007 {"nz", false, false, false}
4010 {"posx", false, false, false},
4011 {"negx", false, false, false},
4012 {"posy", false, false, false},
4013 {"negy", false, false, false},
4014 {"posz", false, false, false},
4015 {"negz", false, false, false}
4018 {"rt", true, false, true},
4019 {"lf", false, true, true},
4020 {"ft", true, true, false},
4021 {"bk", false, false, false},
4022 {"up", true, false, true},
4023 {"dn", true, false, true}
4027 static int componentorder[4] = {0, 1, 2, 3};
4029 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4031 int i, j, cubemapsize;
4032 unsigned char *cubemappixels, *image_buffer;
4033 rtexture_t *cubemaptexture;
4035 // must start 0 so the first loadimagepixels has no requested width/height
4037 cubemappixels = NULL;
4038 cubemaptexture = NULL;
4039 // keep trying different suffix groups (posx, px, rt) until one loads
4040 for (j = 0;j < 3 && !cubemappixels;j++)
4042 // load the 6 images in the suffix group
4043 for (i = 0;i < 6;i++)
4045 // generate an image name based on the base and and suffix
4046 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4048 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4050 // an image loaded, make sure width and height are equal
4051 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4053 // if this is the first image to load successfully, allocate the cubemap memory
4054 if (!cubemappixels && image_width >= 1)
4056 cubemapsize = image_width;
4057 // note this clears to black, so unavailable sides are black
4058 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4060 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4062 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);
4065 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4067 Mem_Free(image_buffer);
4071 // if a cubemap loaded, upload it
4074 if (developer_loading.integer)
4075 Con_Printf("loading cubemap \"%s\"\n", basename);
4077 if (!r_shadow_filters_texturepool)
4078 r_shadow_filters_texturepool = R_AllocTexturePool();
4079 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4080 Mem_Free(cubemappixels);
4084 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4085 if (developer_loading.integer)
4087 Con_Printf("(tried tried images ");
4088 for (j = 0;j < 3;j++)
4089 for (i = 0;i < 6;i++)
4090 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4091 Con_Print(" and was unable to find any of them).\n");
4094 return cubemaptexture;
4097 rtexture_t *R_Shadow_Cubemap(const char *basename)
4100 for (i = 0;i < numcubemaps;i++)
4101 if (!strcasecmp(cubemaps[i].basename, basename))
4102 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4103 if (i >= MAX_CUBEMAPS)
4104 return r_texture_whitecube;
4106 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4107 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4108 return cubemaps[i].texture;
4111 void R_Shadow_FreeCubemaps(void)
4114 for (i = 0;i < numcubemaps;i++)
4116 if (developer_loading.integer)
4117 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4118 if (cubemaps[i].texture)
4119 R_FreeTexture(cubemaps[i].texture);
4123 R_FreeTexturePool(&r_shadow_filters_texturepool);
4126 dlight_t *R_Shadow_NewWorldLight(void)
4128 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4131 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)
4134 // validate parameters
4135 if (style < 0 || style >= MAX_LIGHTSTYLES)
4137 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4143 // copy to light properties
4144 VectorCopy(origin, light->origin);
4145 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4146 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4147 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4148 light->color[0] = max(color[0], 0);
4149 light->color[1] = max(color[1], 0);
4150 light->color[2] = max(color[2], 0);
4151 light->radius = max(radius, 0);
4152 light->style = style;
4153 light->shadow = shadowenable;
4154 light->corona = corona;
4155 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4156 light->coronasizescale = coronasizescale;
4157 light->ambientscale = ambientscale;
4158 light->diffusescale = diffusescale;
4159 light->specularscale = specularscale;
4160 light->flags = flags;
4162 // update renderable light data
4163 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4164 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);
4167 void R_Shadow_FreeWorldLight(dlight_t *light)
4169 if (r_shadow_selectedlight == light)
4170 r_shadow_selectedlight = NULL;
4171 R_RTLight_Uncompile(&light->rtlight);
4172 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4175 void R_Shadow_ClearWorldLights(void)
4179 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4180 for (lightindex = 0;lightindex < range;lightindex++)
4182 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4184 R_Shadow_FreeWorldLight(light);
4186 r_shadow_selectedlight = NULL;
4187 R_Shadow_FreeCubemaps();
4190 void R_Shadow_SelectLight(dlight_t *light)
4192 if (r_shadow_selectedlight)
4193 r_shadow_selectedlight->selected = false;
4194 r_shadow_selectedlight = light;
4195 if (r_shadow_selectedlight)
4196 r_shadow_selectedlight->selected = true;
4199 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4201 // this is never batched (there can be only one)
4202 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);
4205 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4212 // this is never batched (due to the ent parameter changing every time)
4213 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4214 const dlight_t *light = (dlight_t *)ent;
4217 VectorScale(light->color, intensity, spritecolor);
4218 if (VectorLength(spritecolor) < 0.1732f)
4219 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4220 if (VectorLength(spritecolor) > 1.0f)
4221 VectorNormalize(spritecolor);
4223 // draw light sprite
4224 if (light->cubemapname[0] && !light->shadow)
4225 pic = r_editlights_sprcubemapnoshadowlight;
4226 else if (light->cubemapname[0])
4227 pic = r_editlights_sprcubemaplight;
4228 else if (!light->shadow)
4229 pic = r_editlights_sprnoshadowlight;
4231 pic = r_editlights_sprlight;
4232 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);
4233 // draw selection sprite if light is selected
4234 if (light->selected)
4235 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);
4236 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4239 void R_Shadow_DrawLightSprites(void)
4243 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4244 for (lightindex = 0;lightindex < range;lightindex++)
4246 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4248 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4250 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4253 void R_Shadow_SelectLightInView(void)
4255 float bestrating, rating, temp[3];
4259 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4262 for (lightindex = 0;lightindex < range;lightindex++)
4264 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4267 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4268 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4271 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4272 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)
4274 bestrating = rating;
4279 R_Shadow_SelectLight(best);
4282 void R_Shadow_LoadWorldLights(void)
4284 int n, a, style, shadow, flags;
4285 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4286 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4287 if (cl.worldmodel == NULL)
4289 Con_Print("No map loaded.\n");
4292 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4293 strlcat (name, ".rtlights", sizeof (name));
4294 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4304 for (;COM_Parse(t, true) && strcmp(
4305 if (COM_Parse(t, true))
4307 if (com_token[0] == '!')
4310 origin[0] = atof(com_token+1);
4313 origin[0] = atof(com_token);
4318 while (*s && *s != '\n' && *s != '\r')
4324 // check for modifier flags
4331 #if _MSC_VER >= 1400
4332 #define sscanf sscanf_s
4334 cubemapname[sizeof(cubemapname)-1] = 0;
4335 #if MAX_QPATH != 128
4336 #error update this code if MAX_QPATH changes
4338 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
4339 #if _MSC_VER >= 1400
4340 , sizeof(cubemapname)
4342 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4345 flags = LIGHTFLAG_REALTIMEMODE;
4353 coronasizescale = 0.25f;
4355 VectorClear(angles);
4358 if (a < 9 || !strcmp(cubemapname, "\"\""))
4360 // remove quotes on cubemapname
4361 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4364 namelen = strlen(cubemapname) - 2;
4365 memmove(cubemapname, cubemapname + 1, namelen);
4366 cubemapname[namelen] = '\0';
4370 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);
4373 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4381 Con_Printf("invalid rtlights file \"%s\"\n", name);
4382 Mem_Free(lightsstring);
4386 void R_Shadow_SaveWorldLights(void)
4390 size_t bufchars, bufmaxchars;
4392 char name[MAX_QPATH];
4393 char line[MAX_INPUTLINE];
4394 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4395 // I hate lines which are 3 times my screen size :( --blub
4398 if (cl.worldmodel == NULL)
4400 Con_Print("No map loaded.\n");
4403 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4404 strlcat (name, ".rtlights", sizeof (name));
4405 bufchars = bufmaxchars = 0;
4407 for (lightindex = 0;lightindex < range;lightindex++)
4409 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4412 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4413 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);
4414 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4415 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]);
4417 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);
4418 if (bufchars + strlen(line) > bufmaxchars)
4420 bufmaxchars = bufchars + strlen(line) + 2048;
4422 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4426 memcpy(buf, oldbuf, bufchars);
4432 memcpy(buf + bufchars, line, strlen(line));
4433 bufchars += strlen(line);
4437 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4442 void R_Shadow_LoadLightsFile(void)
4445 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4446 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4447 if (cl.worldmodel == NULL)
4449 Con_Print("No map loaded.\n");
4452 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4453 strlcat (name, ".lights", sizeof (name));
4454 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4462 while (*s && *s != '\n' && *s != '\r')
4468 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);
4472 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);
4475 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4476 radius = bound(15, radius, 4096);
4477 VectorScale(color, (2.0f / (8388608.0f)), color);
4478 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4486 Con_Printf("invalid lights file \"%s\"\n", name);
4487 Mem_Free(lightsstring);
4491 // tyrlite/hmap2 light types in the delay field
4492 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4494 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4496 int entnum, style, islight, skin, pflags, effects, type, n;
4499 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4500 char key[256], value[MAX_INPUTLINE];
4502 if (cl.worldmodel == NULL)
4504 Con_Print("No map loaded.\n");
4507 // try to load a .ent file first
4508 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4509 strlcat (key, ".ent", sizeof (key));
4510 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4511 // and if that is not found, fall back to the bsp file entity string
4513 data = cl.worldmodel->brush.entities;
4516 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4518 type = LIGHTTYPE_MINUSX;
4519 origin[0] = origin[1] = origin[2] = 0;
4520 originhack[0] = originhack[1] = originhack[2] = 0;
4521 angles[0] = angles[1] = angles[2] = 0;
4522 color[0] = color[1] = color[2] = 1;
4523 light[0] = light[1] = light[2] = 1;light[3] = 300;
4524 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4534 if (!COM_ParseToken_Simple(&data, false, false))
4536 if (com_token[0] == '}')
4537 break; // end of entity
4538 if (com_token[0] == '_')
4539 strlcpy(key, com_token + 1, sizeof(key));
4541 strlcpy(key, com_token, sizeof(key));
4542 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4543 key[strlen(key)-1] = 0;
4544 if (!COM_ParseToken_Simple(&data, false, false))
4546 strlcpy(value, com_token, sizeof(value));
4548 // now that we have the key pair worked out...
4549 if (!strcmp("light", key))
4551 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4555 light[0] = vec[0] * (1.0f / 256.0f);
4556 light[1] = vec[0] * (1.0f / 256.0f);
4557 light[2] = vec[0] * (1.0f / 256.0f);
4563 light[0] = vec[0] * (1.0f / 255.0f);
4564 light[1] = vec[1] * (1.0f / 255.0f);
4565 light[2] = vec[2] * (1.0f / 255.0f);
4569 else if (!strcmp("delay", key))
4571 else if (!strcmp("origin", key))
4572 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4573 else if (!strcmp("angle", key))
4574 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4575 else if (!strcmp("angles", key))
4576 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4577 else if (!strcmp("color", key))
4578 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4579 else if (!strcmp("wait", key))
4580 fadescale = atof(value);
4581 else if (!strcmp("classname", key))
4583 if (!strncmp(value, "light", 5))
4586 if (!strcmp(value, "light_fluoro"))
4591 overridecolor[0] = 1;
4592 overridecolor[1] = 1;
4593 overridecolor[2] = 1;
4595 if (!strcmp(value, "light_fluorospark"))
4600 overridecolor[0] = 1;
4601 overridecolor[1] = 1;
4602 overridecolor[2] = 1;
4604 if (!strcmp(value, "light_globe"))
4609 overridecolor[0] = 1;
4610 overridecolor[1] = 0.8;
4611 overridecolor[2] = 0.4;
4613 if (!strcmp(value, "light_flame_large_yellow"))
4618 overridecolor[0] = 1;
4619 overridecolor[1] = 0.5;
4620 overridecolor[2] = 0.1;
4622 if (!strcmp(value, "light_flame_small_yellow"))
4627 overridecolor[0] = 1;
4628 overridecolor[1] = 0.5;
4629 overridecolor[2] = 0.1;
4631 if (!strcmp(value, "light_torch_small_white"))
4636 overridecolor[0] = 1;
4637 overridecolor[1] = 0.5;
4638 overridecolor[2] = 0.1;
4640 if (!strcmp(value, "light_torch_small_walltorch"))
4645 overridecolor[0] = 1;
4646 overridecolor[1] = 0.5;
4647 overridecolor[2] = 0.1;
4651 else if (!strcmp("style", key))
4652 style = atoi(value);
4653 else if (!strcmp("skin", key))
4654 skin = (int)atof(value);
4655 else if (!strcmp("pflags", key))
4656 pflags = (int)atof(value);
4657 else if (!strcmp("effects", key))
4658 effects = (int)atof(value);
4659 else if (cl.worldmodel->type == mod_brushq3)
4661 if (!strcmp("scale", key))
4662 lightscale = atof(value);
4663 if (!strcmp("fade", key))
4664 fadescale = atof(value);
4669 if (lightscale <= 0)
4673 if (color[0] == color[1] && color[0] == color[2])
4675 color[0] *= overridecolor[0];
4676 color[1] *= overridecolor[1];
4677 color[2] *= overridecolor[2];
4679 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4680 color[0] = color[0] * light[0];
4681 color[1] = color[1] * light[1];
4682 color[2] = color[2] * light[2];
4685 case LIGHTTYPE_MINUSX:
4687 case LIGHTTYPE_RECIPX:
4689 VectorScale(color, (1.0f / 16.0f), color);
4691 case LIGHTTYPE_RECIPXX:
4693 VectorScale(color, (1.0f / 16.0f), color);
4696 case LIGHTTYPE_NONE:
4700 case LIGHTTYPE_MINUSXX:
4703 VectorAdd(origin, originhack, origin);
4705 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);
4708 Mem_Free(entfiledata);
4712 void R_Shadow_SetCursorLocationForView(void)
4715 vec3_t dest, endpos;
4717 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4718 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4719 if (trace.fraction < 1)
4721 dist = trace.fraction * r_editlights_cursordistance.value;
4722 push = r_editlights_cursorpushback.value;
4726 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4727 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4731 VectorClear( endpos );
4733 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4734 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4735 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4738 void R_Shadow_UpdateWorldLightSelection(void)
4740 if (r_editlights.integer)
4742 R_Shadow_SetCursorLocationForView();
4743 R_Shadow_SelectLightInView();
4746 R_Shadow_SelectLight(NULL);
4749 void R_Shadow_EditLights_Clear_f(void)
4751 R_Shadow_ClearWorldLights();
4754 void R_Shadow_EditLights_Reload_f(void)
4758 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4759 R_Shadow_ClearWorldLights();
4760 R_Shadow_LoadWorldLights();
4761 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4763 R_Shadow_LoadLightsFile();
4764 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4765 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4769 void R_Shadow_EditLights_Save_f(void)
4773 R_Shadow_SaveWorldLights();
4776 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4778 R_Shadow_ClearWorldLights();
4779 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4782 void R_Shadow_EditLights_ImportLightsFile_f(void)
4784 R_Shadow_ClearWorldLights();
4785 R_Shadow_LoadLightsFile();
4788 void R_Shadow_EditLights_Spawn_f(void)
4791 if (!r_editlights.integer)
4793 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4796 if (Cmd_Argc() != 1)
4798 Con_Print("r_editlights_spawn does not take parameters\n");
4801 color[0] = color[1] = color[2] = 1;
4802 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4805 void R_Shadow_EditLights_Edit_f(void)
4807 vec3_t origin, angles, color;
4808 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4809 int style, shadows, flags, normalmode, realtimemode;
4810 char cubemapname[MAX_INPUTLINE];
4811 if (!r_editlights.integer)
4813 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4816 if (!r_shadow_selectedlight)
4818 Con_Print("No selected light.\n");
4821 VectorCopy(r_shadow_selectedlight->origin, origin);
4822 VectorCopy(r_shadow_selectedlight->angles, angles);
4823 VectorCopy(r_shadow_selectedlight->color, color);
4824 radius = r_shadow_selectedlight->radius;
4825 style = r_shadow_selectedlight->style;
4826 if (r_shadow_selectedlight->cubemapname)
4827 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4830 shadows = r_shadow_selectedlight->shadow;
4831 corona = r_shadow_selectedlight->corona;
4832 coronasizescale = r_shadow_selectedlight->coronasizescale;
4833 ambientscale = r_shadow_selectedlight->ambientscale;
4834 diffusescale = r_shadow_selectedlight->diffusescale;
4835 specularscale = r_shadow_selectedlight->specularscale;
4836 flags = r_shadow_selectedlight->flags;
4837 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4838 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4839 if (!strcmp(Cmd_Argv(1), "origin"))
4841 if (Cmd_Argc() != 5)
4843 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4846 origin[0] = atof(Cmd_Argv(2));
4847 origin[1] = atof(Cmd_Argv(3));
4848 origin[2] = atof(Cmd_Argv(4));
4850 else if (!strcmp(Cmd_Argv(1), "originx"))
4852 if (Cmd_Argc() != 3)
4854 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4857 origin[0] = atof(Cmd_Argv(2));
4859 else if (!strcmp(Cmd_Argv(1), "originy"))
4861 if (Cmd_Argc() != 3)
4863 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4866 origin[1] = atof(Cmd_Argv(2));
4868 else if (!strcmp(Cmd_Argv(1), "originz"))
4870 if (Cmd_Argc() != 3)
4872 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4875 origin[2] = atof(Cmd_Argv(2));
4877 else if (!strcmp(Cmd_Argv(1), "move"))
4879 if (Cmd_Argc() != 5)
4881 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4884 origin[0] += atof(Cmd_Argv(2));
4885 origin[1] += atof(Cmd_Argv(3));
4886 origin[2] += atof(Cmd_Argv(4));
4888 else if (!strcmp(Cmd_Argv(1), "movex"))
4890 if (Cmd_Argc() != 3)
4892 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4895 origin[0] += atof(Cmd_Argv(2));
4897 else if (!strcmp(Cmd_Argv(1), "movey"))
4899 if (Cmd_Argc() != 3)
4901 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4904 origin[1] += atof(Cmd_Argv(2));
4906 else if (!strcmp(Cmd_Argv(1), "movez"))
4908 if (Cmd_Argc() != 3)
4910 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4913 origin[2] += atof(Cmd_Argv(2));
4915 else if (!strcmp(Cmd_Argv(1), "angles"))
4917 if (Cmd_Argc() != 5)
4919 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4922 angles[0] = atof(Cmd_Argv(2));
4923 angles[1] = atof(Cmd_Argv(3));
4924 angles[2] = atof(Cmd_Argv(4));
4926 else if (!strcmp(Cmd_Argv(1), "anglesx"))
4928 if (Cmd_Argc() != 3)
4930 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4933 angles[0] = atof(Cmd_Argv(2));
4935 else if (!strcmp(Cmd_Argv(1), "anglesy"))
4937 if (Cmd_Argc() != 3)
4939 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4942 angles[1] = atof(Cmd_Argv(2));
4944 else if (!strcmp(Cmd_Argv(1), "anglesz"))
4946 if (Cmd_Argc() != 3)
4948 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4951 angles[2] = atof(Cmd_Argv(2));
4953 else if (!strcmp(Cmd_Argv(1), "color"))
4955 if (Cmd_Argc() != 5)
4957 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
4960 color[0] = atof(Cmd_Argv(2));
4961 color[1] = atof(Cmd_Argv(3));
4962 color[2] = atof(Cmd_Argv(4));
4964 else if (!strcmp(Cmd_Argv(1), "radius"))
4966 if (Cmd_Argc() != 3)
4968 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4971 radius = atof(Cmd_Argv(2));
4973 else if (!strcmp(Cmd_Argv(1), "colorscale"))
4975 if (Cmd_Argc() == 3)
4977 double scale = atof(Cmd_Argv(2));
4984 if (Cmd_Argc() != 5)
4986 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
4989 color[0] *= atof(Cmd_Argv(2));
4990 color[1] *= atof(Cmd_Argv(3));
4991 color[2] *= atof(Cmd_Argv(4));
4994 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
4996 if (Cmd_Argc() != 3)
4998 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5001 radius *= atof(Cmd_Argv(2));
5003 else if (!strcmp(Cmd_Argv(1), "style"))
5005 if (Cmd_Argc() != 3)
5007 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5010 style = atoi(Cmd_Argv(2));
5012 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5016 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5019 if (Cmd_Argc() == 3)
5020 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5024 else if (!strcmp(Cmd_Argv(1), "shadows"))
5026 if (Cmd_Argc() != 3)
5028 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5031 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5033 else if (!strcmp(Cmd_Argv(1), "corona"))
5035 if (Cmd_Argc() != 3)
5037 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5040 corona = atof(Cmd_Argv(2));
5042 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5044 if (Cmd_Argc() != 3)
5046 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5049 coronasizescale = atof(Cmd_Argv(2));
5051 else if (!strcmp(Cmd_Argv(1), "ambient"))
5053 if (Cmd_Argc() != 3)
5055 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5058 ambientscale = atof(Cmd_Argv(2));
5060 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5062 if (Cmd_Argc() != 3)
5064 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5067 diffusescale = atof(Cmd_Argv(2));
5069 else if (!strcmp(Cmd_Argv(1), "specular"))
5071 if (Cmd_Argc() != 3)
5073 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5076 specularscale = atof(Cmd_Argv(2));
5078 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5080 if (Cmd_Argc() != 3)
5082 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5085 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5087 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5089 if (Cmd_Argc() != 3)
5091 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5094 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5098 Con_Print("usage: r_editlights_edit [property] [value]\n");
5099 Con_Print("Selected light's properties:\n");
5100 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5101 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5102 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5103 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5104 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5105 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5106 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5107 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5108 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5109 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5110 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5111 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5112 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5113 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5116 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5117 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5120 void R_Shadow_EditLights_EditAll_f(void)
5126 if (!r_editlights.integer)
5128 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5132 // EditLights doesn't seem to have a "remove" command or something so:
5133 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5134 for (lightindex = 0;lightindex < range;lightindex++)
5136 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5139 R_Shadow_SelectLight(light);
5140 R_Shadow_EditLights_Edit_f();
5144 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5146 int lightnumber, lightcount;
5147 size_t lightindex, range;
5151 if (!r_editlights.integer)
5153 x = vid_conwidth.value - 240;
5155 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5158 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5159 for (lightindex = 0;lightindex < range;lightindex++)
5161 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5164 if (light == r_shadow_selectedlight)
5165 lightnumber = lightindex;
5168 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;
5169 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;
5171 if (r_shadow_selectedlight == NULL)
5173 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;
5174 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;
5175 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;
5176 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;
5177 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;
5178 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;
5179 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;
5180 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;
5181 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;
5182 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;
5183 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;
5184 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;
5185 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;
5186 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;
5187 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;
5190 void R_Shadow_EditLights_ToggleShadow_f(void)
5192 if (!r_editlights.integer)
5194 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5197 if (!r_shadow_selectedlight)
5199 Con_Print("No selected light.\n");
5202 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);
5205 void R_Shadow_EditLights_ToggleCorona_f(void)
5207 if (!r_editlights.integer)
5209 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5212 if (!r_shadow_selectedlight)
5214 Con_Print("No selected light.\n");
5217 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);
5220 void R_Shadow_EditLights_Remove_f(void)
5222 if (!r_editlights.integer)
5224 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5227 if (!r_shadow_selectedlight)
5229 Con_Print("No selected light.\n");
5232 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5233 r_shadow_selectedlight = NULL;
5236 void R_Shadow_EditLights_Help_f(void)
5239 "Documentation on r_editlights system:\n"
5241 "r_editlights : enable/disable editing mode\n"
5242 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5243 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5244 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5245 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5246 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5248 "r_editlights_help : this help\n"
5249 "r_editlights_clear : remove all lights\n"
5250 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5251 "r_editlights_save : save to .rtlights file\n"
5252 "r_editlights_spawn : create a light with default settings\n"
5253 "r_editlights_edit command : edit selected light - more documentation below\n"
5254 "r_editlights_remove : remove selected light\n"
5255 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5256 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5257 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5259 "origin x y z : set light location\n"
5260 "originx x: set x component of light location\n"
5261 "originy y: set y component of light location\n"
5262 "originz z: set z component of light location\n"
5263 "move x y z : adjust light location\n"
5264 "movex x: adjust x component of light location\n"
5265 "movey y: adjust y component of light location\n"
5266 "movez z: adjust z component of light location\n"
5267 "angles x y z : set light angles\n"
5268 "anglesx x: set x component of light angles\n"
5269 "anglesy y: set y component of light angles\n"
5270 "anglesz z: set z component of light angles\n"
5271 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5272 "radius radius : set radius (size) of light\n"
5273 "colorscale grey : multiply color of light (1 does nothing)\n"
5274 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5275 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5276 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5277 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5278 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5279 "shadows 1/0 : turn on/off shadows\n"
5280 "corona n : set corona intensity\n"
5281 "coronasize n : set corona size (0-1)\n"
5282 "ambient n : set ambient intensity (0-1)\n"
5283 "diffuse n : set diffuse intensity (0-1)\n"
5284 "specular n : set specular intensity (0-1)\n"
5285 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5286 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5287 "<nothing> : print light properties to console\n"
5291 void R_Shadow_EditLights_CopyInfo_f(void)
5293 if (!r_editlights.integer)
5295 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5298 if (!r_shadow_selectedlight)
5300 Con_Print("No selected light.\n");
5303 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5304 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5305 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5306 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5307 if (r_shadow_selectedlight->cubemapname)
5308 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5310 r_shadow_bufferlight.cubemapname[0] = 0;
5311 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5312 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5313 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5314 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5315 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5316 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5317 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5320 void R_Shadow_EditLights_PasteInfo_f(void)
5322 if (!r_editlights.integer)
5324 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5327 if (!r_shadow_selectedlight)
5329 Con_Print("No selected light.\n");
5332 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);
5335 void R_Shadow_EditLights_Init(void)
5337 Cvar_RegisterVariable(&r_editlights);
5338 Cvar_RegisterVariable(&r_editlights_cursordistance);
5339 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5340 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5341 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5342 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5343 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5344 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5345 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)");
5346 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5347 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5348 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5349 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)");
5350 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5351 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5352 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5353 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5354 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5355 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5356 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)");
5362 =============================================================================
5366 =============================================================================
5369 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5371 VectorClear(diffusecolor);
5372 VectorClear(diffusenormal);
5374 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5376 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5377 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5380 VectorSet(ambientcolor, 1, 1, 1);
5387 for (i = 0;i < r_refdef.scene.numlights;i++)
5389 light = r_refdef.scene.lights[i];
5390 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5391 f = 1 - VectorLength2(v);
5392 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5393 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);