3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
162 R_SHADOW_RENDERMODE_SHADOWMAP2D,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 float r_shadow_shadowmap_bias;
175 float r_shadow_shadowmap_texturescale[2];
176 float r_shadow_shadowmap_parameters[4];
177 int r_shadow_drawbuffer;
178 int r_shadow_readbuffer;
179 GLuint r_shadow_fborectangle;
180 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
181 GLuint r_shadow_fbo2d;
182 int r_shadow_shadowmode;
183 int r_shadow_shadowmapmaxsize;
184 int r_shadow_lightscissor[4];
186 int maxshadowtriangles;
189 int maxshadowvertices;
190 float *shadowvertex3f;
203 int r_shadow_buffer_numleafpvsbytes;
204 unsigned char *r_shadow_buffer_visitingleafpvs;
205 unsigned char *r_shadow_buffer_leafpvs;
206 int *r_shadow_buffer_leaflist;
208 int r_shadow_buffer_numsurfacepvsbytes;
209 unsigned char *r_shadow_buffer_surfacepvs;
210 int *r_shadow_buffer_surfacelist;
212 int r_shadow_buffer_numshadowtrispvsbytes;
213 unsigned char *r_shadow_buffer_shadowtrispvs;
214 int r_shadow_buffer_numlighttrispvsbytes;
215 unsigned char *r_shadow_buffer_lighttrispvs;
217 rtexturepool_t *r_shadow_texturepool;
218 rtexture_t *r_shadow_attenuationgradienttexture;
219 rtexture_t *r_shadow_attenuation2dtexture;
220 rtexture_t *r_shadow_attenuation3dtexture;
221 rtexture_t *r_shadow_lightcorona;
222 rtexture_t *r_shadow_shadowmaprectangletexture;
223 rtexture_t *r_shadow_shadowmap2dtexture;
224 rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
225 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
226 int r_shadow_shadowmapsize; // changes for each light based on distance
227 int r_shadow_shadowmaplod; // changes for each light based on distance
229 // lights are reloaded when this changes
230 char r_shadow_mapname[MAX_QPATH];
232 // used only for light filters (cubemaps)
233 rtexturepool_t *r_shadow_filters_texturepool;
235 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
236 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
237 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
238 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
239 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
240 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
241 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
242 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
243 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
244 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
245 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
246 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
247 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
248 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
249 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
250 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
251 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
252 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
253 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
254 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
255 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
256 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
257 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
258 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
259 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
260 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
261 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
262 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
263 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
264 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
265 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
266 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"};
267 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
268 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
269 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
270 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
271 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
272 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
273 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
274 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
275 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
276 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
277 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
278 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
279 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
280 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
281 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
282 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
283 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
284 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
285 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
286 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
287 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
289 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
290 #define ATTENTABLESIZE 256
291 // 1D gradient, 2D circle and 3D sphere attenuation textures
292 #define ATTEN1DSIZE 32
293 #define ATTEN2DSIZE 64
294 #define ATTEN3DSIZE 32
296 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
297 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
298 static float r_shadow_attentable[ATTENTABLESIZE+1];
300 rtlight_t *r_shadow_compilingrtlight;
301 static memexpandablearray_t r_shadow_worldlightsarray;
302 dlight_t *r_shadow_selectedlight;
303 dlight_t r_shadow_bufferlight;
304 vec3_t r_editlights_cursorlocation;
306 extern int con_vislines;
308 typedef struct cubemapinfo_s
315 #define MAX_CUBEMAPS 256
316 static int numcubemaps;
317 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
319 void R_Shadow_UncompileWorldLights(void);
320 void R_Shadow_ClearWorldLights(void);
321 void R_Shadow_SaveWorldLights(void);
322 void R_Shadow_LoadWorldLights(void);
323 void R_Shadow_LoadLightsFile(void);
324 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
325 void R_Shadow_EditLights_Reload_f(void);
326 void R_Shadow_ValidateCvars(void);
327 static void R_Shadow_MakeTextures(void);
329 // VorteX: custom editor light sprites
330 #define EDLIGHTSPRSIZE 8
331 cachepic_t *r_editlights_sprcursor;
332 cachepic_t *r_editlights_sprlight;
333 cachepic_t *r_editlights_sprnoshadowlight;
334 cachepic_t *r_editlights_sprcubemaplight;
335 cachepic_t *r_editlights_sprcubemapnoshadowlight;
336 cachepic_t *r_editlights_sprselection;
338 void R_Shadow_FreeShadowMaps(void)
342 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
343 r_shadow_shadowmode = r_shadow_shadowmapping.integer;
344 r_shadow_shadowmaplod = -1;
347 if (r_shadow_fborectangle)
348 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
349 r_shadow_fborectangle = 0;
353 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
357 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
358 if (r_shadow_fbocubeside[i][0])
359 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
360 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
363 if (r_shadow_shadowmaprectangletexture)
364 R_FreeTexture(r_shadow_shadowmaprectangletexture);
365 r_shadow_shadowmaprectangletexture = NULL;
367 if (r_shadow_shadowmap2dtexture)
368 R_FreeTexture(r_shadow_shadowmap2dtexture);
369 r_shadow_shadowmap2dtexture = NULL;
371 if (r_shadow_shadowmapcubeprojectiontexture)
372 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
373 r_shadow_shadowmapcubeprojectiontexture = NULL;
375 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
376 if (r_shadow_shadowmapcubetexture[i])
377 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
378 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
383 void r_shadow_start(void)
385 // allocate vertex processing arrays
387 r_shadow_attenuationgradienttexture = NULL;
388 r_shadow_attenuation2dtexture = NULL;
389 r_shadow_attenuation3dtexture = NULL;
390 r_shadow_shadowmaprectangletexture = NULL;
391 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
392 r_shadow_shadowmapcubeprojectiontexture = NULL;
393 r_shadow_shadowmap2dtexture = NULL;
394 r_shadow_shadowmapmaxsize = 0;
395 r_shadow_shadowmapsize = 0;
396 r_shadow_shadowmaplod = 0;
397 r_shadow_fborectangle = 0;
398 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
401 R_Shadow_FreeShadowMaps();
403 r_shadow_texturepool = NULL;
404 r_shadow_filters_texturepool = NULL;
405 R_Shadow_ValidateCvars();
406 R_Shadow_MakeTextures();
407 maxshadowtriangles = 0;
408 shadowelements = NULL;
409 maxshadowvertices = 0;
410 shadowvertex3f = NULL;
418 shadowmarklist = NULL;
420 r_shadow_buffer_numleafpvsbytes = 0;
421 r_shadow_buffer_visitingleafpvs = NULL;
422 r_shadow_buffer_leafpvs = NULL;
423 r_shadow_buffer_leaflist = NULL;
424 r_shadow_buffer_numsurfacepvsbytes = 0;
425 r_shadow_buffer_surfacepvs = NULL;
426 r_shadow_buffer_surfacelist = NULL;
427 r_shadow_buffer_numshadowtrispvsbytes = 0;
428 r_shadow_buffer_shadowtrispvs = NULL;
429 r_shadow_buffer_numlighttrispvsbytes = 0;
430 r_shadow_buffer_lighttrispvs = NULL;
433 void r_shadow_shutdown(void)
436 R_Shadow_UncompileWorldLights();
438 R_Shadow_FreeShadowMaps();
442 r_shadow_attenuationgradienttexture = NULL;
443 r_shadow_attenuation2dtexture = NULL;
444 r_shadow_attenuation3dtexture = NULL;
445 R_FreeTexturePool(&r_shadow_texturepool);
446 R_FreeTexturePool(&r_shadow_filters_texturepool);
447 maxshadowtriangles = 0;
449 Mem_Free(shadowelements);
450 shadowelements = NULL;
452 Mem_Free(shadowvertex3f);
453 shadowvertex3f = NULL;
456 Mem_Free(vertexupdate);
459 Mem_Free(vertexremap);
465 Mem_Free(shadowmark);
468 Mem_Free(shadowmarklist);
469 shadowmarklist = NULL;
471 r_shadow_buffer_numleafpvsbytes = 0;
472 if (r_shadow_buffer_visitingleafpvs)
473 Mem_Free(r_shadow_buffer_visitingleafpvs);
474 r_shadow_buffer_visitingleafpvs = NULL;
475 if (r_shadow_buffer_leafpvs)
476 Mem_Free(r_shadow_buffer_leafpvs);
477 r_shadow_buffer_leafpvs = NULL;
478 if (r_shadow_buffer_leaflist)
479 Mem_Free(r_shadow_buffer_leaflist);
480 r_shadow_buffer_leaflist = NULL;
481 r_shadow_buffer_numsurfacepvsbytes = 0;
482 if (r_shadow_buffer_surfacepvs)
483 Mem_Free(r_shadow_buffer_surfacepvs);
484 r_shadow_buffer_surfacepvs = NULL;
485 if (r_shadow_buffer_surfacelist)
486 Mem_Free(r_shadow_buffer_surfacelist);
487 r_shadow_buffer_surfacelist = NULL;
488 r_shadow_buffer_numshadowtrispvsbytes = 0;
489 if (r_shadow_buffer_shadowtrispvs)
490 Mem_Free(r_shadow_buffer_shadowtrispvs);
491 r_shadow_buffer_numlighttrispvsbytes = 0;
492 if (r_shadow_buffer_lighttrispvs)
493 Mem_Free(r_shadow_buffer_lighttrispvs);
496 void r_shadow_newmap(void)
498 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
499 R_Shadow_EditLights_Reload_f();
502 void R_Shadow_Help_f(void)
505 "Documentation on r_shadow system:\n"
507 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
508 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
509 "r_shadow_debuglight : render only this light number (-1 = all)\n"
510 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
511 "r_shadow_gloss2intensity : brightness of forced gloss\n"
512 "r_shadow_glossintensity : brightness of textured gloss\n"
513 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
514 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
515 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
516 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
517 "r_shadow_portallight : use portal visibility for static light precomputation\n"
518 "r_shadow_projectdistance : shadow volume projection distance\n"
519 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
520 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
521 "r_shadow_realtime_world : use high quality world lighting mode\n"
522 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
523 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
524 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
525 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
526 "r_shadow_scissor : use scissor optimization\n"
527 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
528 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
529 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
530 "r_showlighting : useful for performance testing; bright = slow!\n"
531 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
533 "r_shadow_help : this help\n"
537 void R_Shadow_Init(void)
539 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
540 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
541 Cvar_RegisterVariable(&r_shadow_usenormalmap);
542 Cvar_RegisterVariable(&r_shadow_debuglight);
543 Cvar_RegisterVariable(&r_shadow_gloss);
544 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
545 Cvar_RegisterVariable(&r_shadow_glossintensity);
546 Cvar_RegisterVariable(&r_shadow_glossexponent);
547 Cvar_RegisterVariable(&r_shadow_glossexact);
548 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
549 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
550 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
551 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
552 Cvar_RegisterVariable(&r_shadow_portallight);
553 Cvar_RegisterVariable(&r_shadow_projectdistance);
554 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
555 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
556 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
557 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
558 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
559 Cvar_RegisterVariable(&r_shadow_realtime_world);
560 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
561 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
562 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
563 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
564 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
565 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
566 Cvar_RegisterVariable(&r_shadow_scissor);
567 Cvar_RegisterVariable(&r_shadow_shadowmapping);
568 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
569 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
570 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
571 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
572 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
573 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
574 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
575 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
576 Cvar_RegisterVariable(&r_shadow_culltriangles);
577 Cvar_RegisterVariable(&r_shadow_polygonfactor);
578 Cvar_RegisterVariable(&r_shadow_polygonoffset);
579 Cvar_RegisterVariable(&r_shadow_texture3d);
580 Cvar_RegisterVariable(&r_coronas);
581 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
582 Cvar_RegisterVariable(&r_coronas_occlusionquery);
583 Cvar_RegisterVariable(&gl_flashblend);
584 Cvar_RegisterVariable(&gl_ext_separatestencil);
585 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
586 if (gamemode == GAME_TENEBRAE)
588 Cvar_SetValue("r_shadow_gloss", 2);
589 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
591 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
592 R_Shadow_EditLights_Init();
593 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
594 maxshadowtriangles = 0;
595 shadowelements = NULL;
596 maxshadowvertices = 0;
597 shadowvertex3f = NULL;
605 shadowmarklist = NULL;
607 r_shadow_buffer_numleafpvsbytes = 0;
608 r_shadow_buffer_visitingleafpvs = NULL;
609 r_shadow_buffer_leafpvs = NULL;
610 r_shadow_buffer_leaflist = NULL;
611 r_shadow_buffer_numsurfacepvsbytes = 0;
612 r_shadow_buffer_surfacepvs = NULL;
613 r_shadow_buffer_surfacelist = NULL;
614 r_shadow_buffer_shadowtrispvs = NULL;
615 r_shadow_buffer_lighttrispvs = NULL;
616 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
619 matrix4x4_t matrix_attenuationxyz =
622 {0.5, 0.0, 0.0, 0.5},
623 {0.0, 0.5, 0.0, 0.5},
624 {0.0, 0.0, 0.5, 0.5},
629 matrix4x4_t matrix_attenuationz =
632 {0.0, 0.0, 0.5, 0.5},
633 {0.0, 0.0, 0.0, 0.5},
634 {0.0, 0.0, 0.0, 0.5},
639 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
641 // make sure shadowelements is big enough for this volume
642 if (maxshadowtriangles < numtriangles)
644 maxshadowtriangles = numtriangles;
646 Mem_Free(shadowelements);
647 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
649 // make sure shadowvertex3f is big enough for this volume
650 if (maxshadowvertices < numvertices)
652 maxshadowvertices = numvertices;
654 Mem_Free(shadowvertex3f);
655 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
659 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
661 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
662 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
663 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
664 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
665 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
667 if (r_shadow_buffer_visitingleafpvs)
668 Mem_Free(r_shadow_buffer_visitingleafpvs);
669 if (r_shadow_buffer_leafpvs)
670 Mem_Free(r_shadow_buffer_leafpvs);
671 if (r_shadow_buffer_leaflist)
672 Mem_Free(r_shadow_buffer_leaflist);
673 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
674 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
675 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
676 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
678 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
680 if (r_shadow_buffer_surfacepvs)
681 Mem_Free(r_shadow_buffer_surfacepvs);
682 if (r_shadow_buffer_surfacelist)
683 Mem_Free(r_shadow_buffer_surfacelist);
684 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
685 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
686 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
688 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
690 if (r_shadow_buffer_shadowtrispvs)
691 Mem_Free(r_shadow_buffer_shadowtrispvs);
692 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
693 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
695 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
697 if (r_shadow_buffer_lighttrispvs)
698 Mem_Free(r_shadow_buffer_lighttrispvs);
699 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
700 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
704 void R_Shadow_PrepareShadowMark(int numtris)
706 // make sure shadowmark is big enough for this volume
707 if (maxshadowmark < numtris)
709 maxshadowmark = numtris;
711 Mem_Free(shadowmark);
713 Mem_Free(shadowmarklist);
714 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
715 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
719 // if shadowmarkcount wrapped we clear the array and adjust accordingly
720 if (shadowmarkcount == 0)
723 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
728 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)
731 int outtriangles = 0, outvertices = 0;
734 float ratio, direction[3], projectvector[3];
736 if (projectdirection)
737 VectorScale(projectdirection, projectdistance, projectvector);
739 VectorClear(projectvector);
741 // create the vertices
742 if (projectdirection)
744 for (i = 0;i < numshadowmarktris;i++)
746 element = inelement3i + shadowmarktris[i] * 3;
747 for (j = 0;j < 3;j++)
749 if (vertexupdate[element[j]] != vertexupdatenum)
751 vertexupdate[element[j]] = vertexupdatenum;
752 vertexremap[element[j]] = outvertices;
753 vertex = invertex3f + element[j] * 3;
754 // project one copy of the vertex according to projectvector
755 VectorCopy(vertex, outvertex3f);
756 VectorAdd(vertex, projectvector, (outvertex3f + 3));
765 for (i = 0;i < numshadowmarktris;i++)
767 element = inelement3i + shadowmarktris[i] * 3;
768 for (j = 0;j < 3;j++)
770 if (vertexupdate[element[j]] != vertexupdatenum)
772 vertexupdate[element[j]] = vertexupdatenum;
773 vertexremap[element[j]] = outvertices;
774 vertex = invertex3f + element[j] * 3;
775 // project one copy of the vertex to the sphere radius of the light
776 // (FIXME: would projecting it to the light box be better?)
777 VectorSubtract(vertex, projectorigin, direction);
778 ratio = projectdistance / VectorLength(direction);
779 VectorCopy(vertex, outvertex3f);
780 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
788 if (r_shadow_frontsidecasting.integer)
790 for (i = 0;i < numshadowmarktris;i++)
792 int remappedelement[3];
794 const int *neighbortriangle;
796 markindex = shadowmarktris[i] * 3;
797 element = inelement3i + markindex;
798 neighbortriangle = inneighbor3i + markindex;
799 // output the front and back triangles
800 outelement3i[0] = vertexremap[element[0]];
801 outelement3i[1] = vertexremap[element[1]];
802 outelement3i[2] = vertexremap[element[2]];
803 outelement3i[3] = vertexremap[element[2]] + 1;
804 outelement3i[4] = vertexremap[element[1]] + 1;
805 outelement3i[5] = vertexremap[element[0]] + 1;
809 // output the sides (facing outward from this triangle)
810 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
812 remappedelement[0] = vertexremap[element[0]];
813 remappedelement[1] = vertexremap[element[1]];
814 outelement3i[0] = remappedelement[1];
815 outelement3i[1] = remappedelement[0];
816 outelement3i[2] = remappedelement[0] + 1;
817 outelement3i[3] = remappedelement[1];
818 outelement3i[4] = remappedelement[0] + 1;
819 outelement3i[5] = remappedelement[1] + 1;
824 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
826 remappedelement[1] = vertexremap[element[1]];
827 remappedelement[2] = vertexremap[element[2]];
828 outelement3i[0] = remappedelement[2];
829 outelement3i[1] = remappedelement[1];
830 outelement3i[2] = remappedelement[1] + 1;
831 outelement3i[3] = remappedelement[2];
832 outelement3i[4] = remappedelement[1] + 1;
833 outelement3i[5] = remappedelement[2] + 1;
838 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
840 remappedelement[0] = vertexremap[element[0]];
841 remappedelement[2] = vertexremap[element[2]];
842 outelement3i[0] = remappedelement[0];
843 outelement3i[1] = remappedelement[2];
844 outelement3i[2] = remappedelement[2] + 1;
845 outelement3i[3] = remappedelement[0];
846 outelement3i[4] = remappedelement[2] + 1;
847 outelement3i[5] = remappedelement[0] + 1;
856 for (i = 0;i < numshadowmarktris;i++)
858 int remappedelement[3];
860 const int *neighbortriangle;
862 markindex = shadowmarktris[i] * 3;
863 element = inelement3i + markindex;
864 neighbortriangle = inneighbor3i + markindex;
865 // output the front and back triangles
866 outelement3i[0] = vertexremap[element[2]];
867 outelement3i[1] = vertexremap[element[1]];
868 outelement3i[2] = vertexremap[element[0]];
869 outelement3i[3] = vertexremap[element[0]] + 1;
870 outelement3i[4] = vertexremap[element[1]] + 1;
871 outelement3i[5] = vertexremap[element[2]] + 1;
875 // output the sides (facing outward from this triangle)
876 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
878 remappedelement[0] = vertexremap[element[0]];
879 remappedelement[1] = vertexremap[element[1]];
880 outelement3i[0] = remappedelement[0];
881 outelement3i[1] = remappedelement[1];
882 outelement3i[2] = remappedelement[1] + 1;
883 outelement3i[3] = remappedelement[0];
884 outelement3i[4] = remappedelement[1] + 1;
885 outelement3i[5] = remappedelement[0] + 1;
890 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
892 remappedelement[1] = vertexremap[element[1]];
893 remappedelement[2] = vertexremap[element[2]];
894 outelement3i[0] = remappedelement[1];
895 outelement3i[1] = remappedelement[2];
896 outelement3i[2] = remappedelement[2] + 1;
897 outelement3i[3] = remappedelement[1];
898 outelement3i[4] = remappedelement[2] + 1;
899 outelement3i[5] = remappedelement[1] + 1;
904 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
906 remappedelement[0] = vertexremap[element[0]];
907 remappedelement[2] = vertexremap[element[2]];
908 outelement3i[0] = remappedelement[2];
909 outelement3i[1] = remappedelement[0];
910 outelement3i[2] = remappedelement[0] + 1;
911 outelement3i[3] = remappedelement[2];
912 outelement3i[4] = remappedelement[0] + 1;
913 outelement3i[5] = remappedelement[2] + 1;
921 *outnumvertices = outvertices;
925 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)
928 int outtriangles = 0, outvertices = 0;
931 float ratio, direction[3], projectvector[3];
934 if (projectdirection)
935 VectorScale(projectdirection, projectdistance, projectvector);
937 VectorClear(projectvector);
939 for (i = 0;i < numshadowmarktris;i++)
941 int remappedelement[3];
943 const int *neighbortriangle;
945 markindex = shadowmarktris[i] * 3;
946 neighbortriangle = inneighbor3i + markindex;
947 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
948 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
949 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
950 if (side[0] + side[1] + side[2] == 0)
954 element = inelement3i + markindex;
956 // create the vertices
957 for (j = 0;j < 3;j++)
959 if (side[j] + side[j+1] == 0)
962 if (vertexupdate[k] != vertexupdatenum)
964 vertexupdate[k] = vertexupdatenum;
965 vertexremap[k] = outvertices;
966 vertex = invertex3f + k * 3;
967 VectorCopy(vertex, outvertex3f);
968 if (projectdirection)
970 // project one copy of the vertex according to projectvector
971 VectorAdd(vertex, projectvector, (outvertex3f + 3));
975 // project one copy of the vertex to the sphere radius of the light
976 // (FIXME: would projecting it to the light box be better?)
977 VectorSubtract(vertex, projectorigin, direction);
978 ratio = projectdistance / VectorLength(direction);
979 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
986 // output the sides (facing outward from this triangle)
989 remappedelement[0] = vertexremap[element[0]];
990 remappedelement[1] = vertexremap[element[1]];
991 outelement3i[0] = remappedelement[1];
992 outelement3i[1] = remappedelement[0];
993 outelement3i[2] = remappedelement[0] + 1;
994 outelement3i[3] = remappedelement[1];
995 outelement3i[4] = remappedelement[0] + 1;
996 outelement3i[5] = remappedelement[1] + 1;
1003 remappedelement[1] = vertexremap[element[1]];
1004 remappedelement[2] = vertexremap[element[2]];
1005 outelement3i[0] = remappedelement[2];
1006 outelement3i[1] = remappedelement[1];
1007 outelement3i[2] = remappedelement[1] + 1;
1008 outelement3i[3] = remappedelement[2];
1009 outelement3i[4] = remappedelement[1] + 1;
1010 outelement3i[5] = remappedelement[2] + 1;
1017 remappedelement[0] = vertexremap[element[0]];
1018 remappedelement[2] = vertexremap[element[2]];
1019 outelement3i[0] = remappedelement[0];
1020 outelement3i[1] = remappedelement[2];
1021 outelement3i[2] = remappedelement[2] + 1;
1022 outelement3i[3] = remappedelement[0];
1023 outelement3i[4] = remappedelement[2] + 1;
1024 outelement3i[5] = remappedelement[0] + 1;
1031 *outnumvertices = outvertices;
1032 return outtriangles;
1035 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)
1041 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1043 tend = firsttriangle + numtris;
1044 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1046 // surface box entirely inside light box, no box cull
1047 if (projectdirection)
1049 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1051 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1052 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1053 shadowmarklist[numshadowmark++] = t;
1058 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1059 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1060 shadowmarklist[numshadowmark++] = t;
1065 // surface box not entirely inside light box, cull each triangle
1066 if (projectdirection)
1068 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1070 v[0] = invertex3f + e[0] * 3;
1071 v[1] = invertex3f + e[1] * 3;
1072 v[2] = invertex3f + e[2] * 3;
1073 TriangleNormal(v[0], v[1], v[2], normal);
1074 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1075 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1076 shadowmarklist[numshadowmark++] = t;
1081 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1083 v[0] = invertex3f + e[0] * 3;
1084 v[1] = invertex3f + e[1] * 3;
1085 v[2] = invertex3f + e[2] * 3;
1086 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1087 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1088 shadowmarklist[numshadowmark++] = t;
1094 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1099 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1101 // check if the shadow volume intersects the near plane
1103 // a ray between the eye and light origin may intersect the caster,
1104 // indicating that the shadow may touch the eye location, however we must
1105 // test the near plane (a polygon), not merely the eye location, so it is
1106 // easiest to enlarge the caster bounding shape slightly for this.
1112 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)
1114 int i, tris, outverts;
1115 if (projectdistance < 0.1)
1117 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1120 if (!numverts || !nummarktris)
1122 // make sure shadowelements is big enough for this volume
1123 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1124 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1126 if (maxvertexupdate < numverts)
1128 maxvertexupdate = numverts;
1130 Mem_Free(vertexupdate);
1132 Mem_Free(vertexremap);
1133 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1134 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1135 vertexupdatenum = 0;
1138 if (vertexupdatenum == 0)
1140 vertexupdatenum = 1;
1141 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1142 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1145 for (i = 0;i < nummarktris;i++)
1146 shadowmark[marktris[i]] = shadowmarkcount;
1148 if (r_shadow_compilingrtlight)
1150 // if we're compiling an rtlight, capture the mesh
1151 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1152 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1153 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1154 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1158 // decide which type of shadow to generate and set stencil mode
1159 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1160 // generate the sides or a solid volume, depending on type
1161 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1162 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1164 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1165 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1166 r_refdef.stats.lights_shadowtriangles += tris;
1168 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1169 GL_LockArrays(0, outverts);
1170 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1172 // increment stencil if frontface is infront of depthbuffer
1173 GL_CullFace(r_refdef.view.cullface_front);
1174 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1175 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1176 // decrement stencil if backface is infront of depthbuffer
1177 GL_CullFace(r_refdef.view.cullface_back);
1178 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1180 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1182 // decrement stencil if backface is behind depthbuffer
1183 GL_CullFace(r_refdef.view.cullface_front);
1184 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1185 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1186 // increment stencil if frontface is behind depthbuffer
1187 GL_CullFace(r_refdef.view.cullface_back);
1188 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1190 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1191 GL_LockArrays(0, 0);
1196 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)
1198 int i, tris = nummarktris;
1201 if (!numverts || !nummarktris)
1203 // make sure shadowelements is big enough for this mesh
1204 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1205 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1207 // gather up the (sparse) triangles into one array
1208 outelement3i = shadowelements;
1209 for (i = 0;i < nummarktris;i++)
1211 element = elements + marktris[i] * 3;
1212 outelement3i[0] = element[0];
1213 outelement3i[1] = element[1];
1214 outelement3i[2] = element[2];
1218 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1219 r_refdef.stats.lights_shadowtriangles += tris;
1220 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1221 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1224 static void R_Shadow_MakeTextures_MakeCorona(void)
1228 unsigned char pixels[32][32][4];
1229 for (y = 0;y < 32;y++)
1231 dy = (y - 15.5f) * (1.0f / 16.0f);
1232 for (x = 0;x < 32;x++)
1234 dx = (x - 15.5f) * (1.0f / 16.0f);
1235 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1236 a = bound(0, a, 255);
1237 pixels[y][x][0] = a;
1238 pixels[y][x][1] = a;
1239 pixels[y][x][2] = a;
1240 pixels[y][x][3] = 255;
1243 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1246 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1248 float dist = sqrt(x*x+y*y+z*z);
1249 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1250 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1251 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1254 static void R_Shadow_MakeTextures(void)
1257 float intensity, dist;
1259 R_FreeTexturePool(&r_shadow_texturepool);
1260 r_shadow_texturepool = R_AllocTexturePool();
1261 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1262 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1263 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1264 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1265 for (x = 0;x <= ATTENTABLESIZE;x++)
1267 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1268 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1269 r_shadow_attentable[x] = bound(0, intensity, 1);
1271 // 1D gradient texture
1272 for (x = 0;x < ATTEN1DSIZE;x++)
1273 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1274 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);
1275 // 2D circle texture
1276 for (y = 0;y < ATTEN2DSIZE;y++)
1277 for (x = 0;x < ATTEN2DSIZE;x++)
1278 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);
1279 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);
1280 // 3D sphere texture
1281 if (r_shadow_texture3d.integer && gl_texture3d)
1283 for (z = 0;z < ATTEN3DSIZE;z++)
1284 for (y = 0;y < ATTEN3DSIZE;y++)
1285 for (x = 0;x < ATTEN3DSIZE;x++)
1286 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));
1287 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);
1290 r_shadow_attenuation3dtexture = NULL;
1293 R_Shadow_MakeTextures_MakeCorona();
1295 // Editor light sprites
1296 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1297 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1298 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1299 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1300 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1301 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1304 void R_Shadow_ValidateCvars(void)
1306 if (r_shadow_texture3d.integer && !gl_texture3d)
1307 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1308 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1309 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1310 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1311 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1314 void R_Shadow_RenderMode_Begin(void)
1318 R_Shadow_ValidateCvars();
1320 if (!r_shadow_attenuation2dtexture
1321 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1322 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1323 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1324 R_Shadow_MakeTextures();
1327 R_Mesh_ColorPointer(NULL, 0, 0);
1328 R_Mesh_ResetTextureState();
1329 GL_BlendFunc(GL_ONE, GL_ZERO);
1330 GL_DepthRange(0, 1);
1331 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1333 GL_DepthMask(false);
1334 GL_Color(0, 0, 0, 1);
1335 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1337 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1339 if (gl_ext_separatestencil.integer)
1341 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1342 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1344 else if (gl_ext_stenciltwoside.integer)
1346 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1347 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1351 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1352 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1355 if (r_glsl.integer && gl_support_fragment_shader)
1356 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1357 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1358 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1360 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1363 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1364 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1365 r_shadow_drawbuffer = drawbuffer;
1366 r_shadow_readbuffer = readbuffer;
1369 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1371 rsurface.rtlight = rtlight;
1374 void R_Shadow_RenderMode_Reset(void)
1377 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1379 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1381 if (gl_support_ext_framebuffer_object)
1383 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1385 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1386 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1387 R_SetViewport(&r_refdef.view.viewport);
1388 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1389 R_Mesh_ColorPointer(NULL, 0, 0);
1390 R_Mesh_ResetTextureState();
1391 GL_DepthRange(0, 1);
1393 GL_DepthMask(false);
1394 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1395 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1396 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1397 qglStencilMask(~0);CHECKGLERROR
1398 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1399 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1400 GL_CullFace(r_refdef.view.cullface_back);
1401 GL_Color(1, 1, 1, 1);
1402 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1403 GL_BlendFunc(GL_ONE, GL_ZERO);
1404 R_SetupGenericShader(false);
1405 r_shadow_usingshadowmaprect = false;
1406 r_shadow_usingshadowmapcube = false;
1407 r_shadow_usingshadowmap2d = false;
1411 void R_Shadow_ClearStencil(void)
1414 GL_Clear(GL_STENCIL_BUFFER_BIT);
1415 r_refdef.stats.lights_clears++;
1418 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1420 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1421 if (r_shadow_rendermode == mode)
1424 R_Shadow_RenderMode_Reset();
1425 GL_ColorMask(0, 0, 0, 0);
1426 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1427 R_SetupDepthOrShadowShader();
1428 qglDepthFunc(GL_LESS);CHECKGLERROR
1429 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1430 r_shadow_rendermode = mode;
1435 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1436 GL_CullFace(GL_NONE);
1437 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1438 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1440 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1441 GL_CullFace(GL_NONE);
1442 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1443 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1445 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1446 GL_CullFace(GL_NONE);
1447 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1448 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1449 qglStencilMask(~0);CHECKGLERROR
1450 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1451 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1452 qglStencilMask(~0);CHECKGLERROR
1453 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1455 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1456 GL_CullFace(GL_NONE);
1457 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1458 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1459 qglStencilMask(~0);CHECKGLERROR
1460 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1461 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1462 qglStencilMask(~0);CHECKGLERROR
1463 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1468 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1473 float nearclip, farclip;
1474 r_viewport_t viewport;
1476 maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
1477 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1479 r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1480 r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1481 r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1482 r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
1483 r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
1484 if (r_shadow_shadowmapping.integer == 1)
1486 // complex unrolled cube approach (more flexible)
1487 //if (!r_shadow_shadowmapcubeprojectiontexture)
1488 // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1489 if (!r_shadow_shadowmap2dtexture)
1492 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4);
1493 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1494 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1495 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1499 R_Shadow_RenderMode_Reset();
1500 if (r_shadow_shadowmap2dtexture)
1502 // render depth into the fbo, do not render color at all
1503 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1504 qglDrawBuffer(GL_NONE);CHECKGLERROR
1505 qglReadBuffer(GL_NONE);CHECKGLERROR
1506 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1507 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1509 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1510 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1512 R_SetupDepthOrShadowShader();
1516 R_SetupShowDepthShader();
1517 qglClearColor(1,1,1,1);CHECKGLERROR
1519 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1520 r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
1521 r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
1522 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1524 else if (r_shadow_shadowmapping.integer == 2)
1526 // complex unrolled cube approach (more flexible)
1527 //if (!r_shadow_shadowmapcubeprojectiontexture)
1528 // r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1529 if (!r_shadow_shadowmaprectangletexture)
1532 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4);
1533 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1534 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1535 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1539 R_Shadow_RenderMode_Reset();
1540 if (r_shadow_shadowmaprectangletexture)
1542 // render depth into the fbo, do not render color at all
1543 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1544 qglDrawBuffer(GL_NONE);CHECKGLERROR
1545 qglReadBuffer(GL_NONE);CHECKGLERROR
1546 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1547 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1549 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1550 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1552 R_SetupDepthOrShadowShader();
1556 R_SetupShowDepthShader();
1557 qglClearColor(1,1,1,1);CHECKGLERROR
1559 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1560 r_shadow_shadowmap_texturescale[0] = size;
1561 r_shadow_shadowmap_texturescale[1] = size;
1562 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1564 else if (r_shadow_shadowmapping.integer == 3)
1566 // simple cube approach
1567 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1570 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size);
1571 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1572 for (i = 0;i < 6;i++)
1574 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1575 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
1580 R_Shadow_RenderMode_Reset();
1581 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1583 // render depth into the fbo, do not render color at all
1584 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1585 qglDrawBuffer(GL_NONE);CHECKGLERROR
1586 qglReadBuffer(GL_NONE);CHECKGLERROR
1587 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1588 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1590 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1591 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1593 R_SetupDepthOrShadowShader();
1597 R_SetupShowDepthShader();
1598 qglClearColor(1,1,1,1);CHECKGLERROR
1600 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1601 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1602 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1603 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1606 R_SetViewport(&viewport);
1607 GL_PolygonOffset(0, 0);
1608 GL_CullFace(GL_NONE); // quake is backwards
1609 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1612 qglClearDepth(1);CHECKGLERROR
1615 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1619 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1622 R_Shadow_RenderMode_Reset();
1623 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1626 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1630 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1631 // only draw light where this geometry was already rendered AND the
1632 // stencil is 128 (values other than this mean shadow)
1633 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1635 r_shadow_rendermode = r_shadow_lightingrendermode;
1636 // do global setup needed for the chosen lighting mode
1637 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1639 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1640 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1644 if (r_shadow_shadowmapping.integer == 1)
1646 r_shadow_usingshadowmap2d = true;
1647 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1650 else if (r_shadow_shadowmapping.integer == 2)
1652 r_shadow_usingshadowmaprect = true;
1653 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1656 else if (r_shadow_shadowmapping.integer == 3)
1658 r_shadow_usingshadowmapcube = true;
1659 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1664 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1665 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1666 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1670 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1673 R_Shadow_RenderMode_Reset();
1674 GL_BlendFunc(GL_ONE, GL_ONE);
1675 GL_DepthRange(0, 1);
1676 GL_DepthTest(r_showshadowvolumes.integer < 2);
1677 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1678 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1679 GL_CullFace(GL_NONE);
1680 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1683 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1686 R_Shadow_RenderMode_Reset();
1687 GL_BlendFunc(GL_ONE, GL_ONE);
1688 GL_DepthRange(0, 1);
1689 GL_DepthTest(r_showlighting.integer < 2);
1690 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1693 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1697 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1698 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1700 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1703 void R_Shadow_RenderMode_End(void)
1706 R_Shadow_RenderMode_Reset();
1707 R_Shadow_RenderMode_ActiveLight(NULL);
1709 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1710 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1713 int bboxedges[12][2] =
1732 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1734 int i, ix1, iy1, ix2, iy2;
1735 float x1, y1, x2, y2;
1737 float vertex[20][3];
1746 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1747 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1748 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1749 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1751 if (!r_shadow_scissor.integer)
1754 // if view is inside the light box, just say yes it's visible
1755 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1758 x1 = y1 = x2 = y2 = 0;
1760 // transform all corners that are infront of the nearclip plane
1761 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1762 plane4f[3] = r_refdef.view.frustum[4].dist;
1764 for (i = 0;i < 8;i++)
1766 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1767 dist[i] = DotProduct4(corner[i], plane4f);
1768 sign[i] = dist[i] > 0;
1771 VectorCopy(corner[i], vertex[numvertices]);
1775 // if some points are behind the nearclip, add clipped edge points to make
1776 // sure that the scissor boundary is complete
1777 if (numvertices > 0 && numvertices < 8)
1779 // add clipped edge points
1780 for (i = 0;i < 12;i++)
1782 j = bboxedges[i][0];
1783 k = bboxedges[i][1];
1784 if (sign[j] != sign[k])
1786 f = dist[j] / (dist[j] - dist[k]);
1787 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1793 // if we have no points to check, the light is behind the view plane
1797 // if we have some points to transform, check what screen area is covered
1798 x1 = y1 = x2 = y2 = 0;
1800 //Con_Printf("%i vertices to transform...\n", numvertices);
1801 for (i = 0;i < numvertices;i++)
1803 VectorCopy(vertex[i], v);
1804 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1805 //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]);
1808 if (x1 > v2[0]) x1 = v2[0];
1809 if (x2 < v2[0]) x2 = v2[0];
1810 if (y1 > v2[1]) y1 = v2[1];
1811 if (y2 < v2[1]) y2 = v2[1];
1820 // now convert the scissor rectangle to integer screen coordinates
1821 ix1 = (int)(x1 - 1.0f);
1822 iy1 = vid.height - (int)(y2 - 1.0f);
1823 ix2 = (int)(x2 + 1.0f);
1824 iy2 = vid.height - (int)(y1 + 1.0f);
1825 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1827 // clamp it to the screen
1828 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1829 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1830 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1831 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1833 // if it is inside out, it's not visible
1834 if (ix2 <= ix1 || iy2 <= iy1)
1837 // the light area is visible, set up the scissor rectangle
1838 r_shadow_lightscissor[0] = ix1;
1839 r_shadow_lightscissor[1] = iy1;
1840 r_shadow_lightscissor[2] = ix2 - ix1;
1841 r_shadow_lightscissor[3] = iy2 - iy1;
1843 r_refdef.stats.lights_scissored++;
1847 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1849 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1850 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1851 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1852 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1853 if (r_textureunits.integer >= 3)
1855 if (VectorLength2(diffusecolor) > 0)
1857 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1859 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1860 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1861 if ((dot = DotProduct(n, v)) < 0)
1863 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1864 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1867 VectorCopy(ambientcolor, color4f);
1868 if (r_refdef.fogenabled)
1871 f = FogPoint_Model(vertex3f);
1872 VectorScale(color4f, f, color4f);
1879 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1881 VectorCopy(ambientcolor, color4f);
1882 if (r_refdef.fogenabled)
1885 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1886 f = FogPoint_Model(vertex3f);
1887 VectorScale(color4f, f, color4f);
1893 else if (r_textureunits.integer >= 2)
1895 if (VectorLength2(diffusecolor) > 0)
1897 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1899 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1900 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1902 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1903 if ((dot = DotProduct(n, v)) < 0)
1905 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1906 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1907 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1908 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1912 color4f[0] = ambientcolor[0] * distintensity;
1913 color4f[1] = ambientcolor[1] * distintensity;
1914 color4f[2] = ambientcolor[2] * distintensity;
1916 if (r_refdef.fogenabled)
1919 f = FogPoint_Model(vertex3f);
1920 VectorScale(color4f, f, color4f);
1924 VectorClear(color4f);
1930 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1932 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1933 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1935 color4f[0] = ambientcolor[0] * distintensity;
1936 color4f[1] = ambientcolor[1] * distintensity;
1937 color4f[2] = ambientcolor[2] * distintensity;
1938 if (r_refdef.fogenabled)
1941 f = FogPoint_Model(vertex3f);
1942 VectorScale(color4f, f, color4f);
1946 VectorClear(color4f);
1953 if (VectorLength2(diffusecolor) > 0)
1955 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1957 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1958 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1960 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1961 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1962 if ((dot = DotProduct(n, v)) < 0)
1964 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1965 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1966 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1967 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1971 color4f[0] = ambientcolor[0] * distintensity;
1972 color4f[1] = ambientcolor[1] * distintensity;
1973 color4f[2] = ambientcolor[2] * distintensity;
1975 if (r_refdef.fogenabled)
1978 f = FogPoint_Model(vertex3f);
1979 VectorScale(color4f, f, color4f);
1983 VectorClear(color4f);
1989 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1991 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1992 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1994 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1995 color4f[0] = ambientcolor[0] * distintensity;
1996 color4f[1] = ambientcolor[1] * distintensity;
1997 color4f[2] = ambientcolor[2] * distintensity;
1998 if (r_refdef.fogenabled)
2001 f = FogPoint_Model(vertex3f);
2002 VectorScale(color4f, f, color4f);
2006 VectorClear(color4f);
2013 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2015 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2018 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2019 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2020 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2021 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2022 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2024 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2026 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2027 // the cubemap normalizes this for us
2028 out3f[0] = DotProduct(svector3f, lightdir);
2029 out3f[1] = DotProduct(tvector3f, lightdir);
2030 out3f[2] = DotProduct(normal3f, lightdir);
2034 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2037 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2038 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2039 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2040 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2041 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2042 float lightdir[3], eyedir[3], halfdir[3];
2043 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2045 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2046 VectorNormalize(lightdir);
2047 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2048 VectorNormalize(eyedir);
2049 VectorAdd(lightdir, eyedir, halfdir);
2050 // the cubemap normalizes this for us
2051 out3f[0] = DotProduct(svector3f, halfdir);
2052 out3f[1] = DotProduct(tvector3f, halfdir);
2053 out3f[2] = DotProduct(normal3f, halfdir);
2057 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)
2059 // used to display how many times a surface is lit for level design purposes
2060 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2063 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)
2065 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2066 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2067 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2068 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2070 R_Mesh_ColorPointer(NULL, 0, 0);
2071 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2072 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2073 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2074 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2075 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2076 if (rsurface.texture->backgroundcurrentskinframe)
2078 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2079 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2080 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2081 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2083 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2084 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2085 if(rsurface.texture->colormapping)
2087 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2088 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2090 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2091 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2092 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2093 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2094 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2095 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2097 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2099 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2100 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2102 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2106 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)
2108 // shared final code for all the dot3 layers
2110 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2111 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2113 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2114 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2118 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)
2121 // colorscale accounts for how much we multiply the brightness
2124 // mult is how many times the final pass of the lighting will be
2125 // performed to get more brightness than otherwise possible.
2127 // Limit mult to 64 for sanity sake.
2129 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2131 // 3 3D combine path (Geforce3, Radeon 8500)
2132 memset(&m, 0, sizeof(m));
2133 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2134 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2135 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2136 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2137 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2138 m.tex[1] = R_GetTexture(basetexture);
2139 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2140 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2141 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2142 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2143 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2144 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2145 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2146 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2147 m.texmatrix[2] = rsurface.entitytolight;
2148 GL_BlendFunc(GL_ONE, GL_ONE);
2150 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2152 // 2 3D combine path (Geforce3, original Radeon)
2153 memset(&m, 0, sizeof(m));
2154 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2155 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2156 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2157 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2158 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2159 m.tex[1] = R_GetTexture(basetexture);
2160 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2161 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2162 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2163 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2164 GL_BlendFunc(GL_ONE, GL_ONE);
2166 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2168 // 4 2D combine path (Geforce3, Radeon 8500)
2169 memset(&m, 0, sizeof(m));
2170 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2171 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2172 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2173 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2174 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2175 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2176 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2177 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2178 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2179 m.texmatrix[1] = rsurface.entitytoattenuationz;
2180 m.tex[2] = R_GetTexture(basetexture);
2181 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2182 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2183 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2184 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2185 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2187 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2188 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2189 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2190 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2191 m.texmatrix[3] = rsurface.entitytolight;
2193 GL_BlendFunc(GL_ONE, GL_ONE);
2195 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2197 // 3 2D combine path (Geforce3, original Radeon)
2198 memset(&m, 0, sizeof(m));
2199 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2200 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2201 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2202 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2203 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2204 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2205 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2206 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2207 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2208 m.texmatrix[1] = rsurface.entitytoattenuationz;
2209 m.tex[2] = R_GetTexture(basetexture);
2210 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2211 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2212 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2213 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2214 GL_BlendFunc(GL_ONE, GL_ONE);
2218 // 2/2/2 2D combine path (any dot3 card)
2219 memset(&m, 0, sizeof(m));
2220 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2221 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2222 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2223 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2224 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2225 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2226 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2227 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2228 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2229 m.texmatrix[1] = rsurface.entitytoattenuationz;
2230 R_Mesh_TextureState(&m);
2231 GL_ColorMask(0,0,0,1);
2232 GL_BlendFunc(GL_ONE, GL_ZERO);
2233 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2236 memset(&m, 0, sizeof(m));
2237 m.tex[0] = R_GetTexture(basetexture);
2238 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2239 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2240 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2241 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2242 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2244 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2245 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2246 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2247 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2248 m.texmatrix[1] = rsurface.entitytolight;
2250 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2252 // this final code is shared
2253 R_Mesh_TextureState(&m);
2254 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);
2257 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)
2260 // colorscale accounts for how much we multiply the brightness
2263 // mult is how many times the final pass of the lighting will be
2264 // performed to get more brightness than otherwise possible.
2266 // Limit mult to 64 for sanity sake.
2268 // generate normalization cubemap texcoords
2269 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2270 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2272 // 3/2 3D 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.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
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 R_Mesh_TextureState(&m);
2291 GL_ColorMask(0,0,0,1);
2292 GL_BlendFunc(GL_ONE, GL_ZERO);
2293 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2296 memset(&m, 0, sizeof(m));
2297 m.tex[0] = R_GetTexture(basetexture);
2298 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2299 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2300 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2301 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2302 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2304 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2305 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2306 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2307 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2308 m.texmatrix[1] = rsurface.entitytolight;
2310 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2312 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2314 // 1/2/2 3D combine path (original Radeon)
2315 memset(&m, 0, sizeof(m));
2316 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2317 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2318 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2319 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2320 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2321 R_Mesh_TextureState(&m);
2322 GL_ColorMask(0,0,0,1);
2323 GL_BlendFunc(GL_ONE, GL_ZERO);
2324 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2327 memset(&m, 0, sizeof(m));
2328 m.tex[0] = R_GetTexture(normalmaptexture);
2329 m.texcombinergb[0] = GL_REPLACE;
2330 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2331 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2332 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2333 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2334 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2335 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2336 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2337 m.pointer_texcoord_bufferobject[1] = 0;
2338 m.pointer_texcoord_bufferoffset[1] = 0;
2339 R_Mesh_TextureState(&m);
2340 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2341 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2344 memset(&m, 0, sizeof(m));
2345 m.tex[0] = R_GetTexture(basetexture);
2346 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2347 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2348 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2349 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2350 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2352 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2353 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2354 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2355 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2356 m.texmatrix[1] = rsurface.entitytolight;
2358 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2360 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2362 // 2/2 3D combine path (original Radeon)
2363 memset(&m, 0, sizeof(m));
2364 m.tex[0] = R_GetTexture(normalmaptexture);
2365 m.texcombinergb[0] = GL_REPLACE;
2366 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2367 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2368 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2369 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2370 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2371 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2372 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2373 m.pointer_texcoord_bufferobject[1] = 0;
2374 m.pointer_texcoord_bufferoffset[1] = 0;
2375 R_Mesh_TextureState(&m);
2376 GL_ColorMask(0,0,0,1);
2377 GL_BlendFunc(GL_ONE, GL_ZERO);
2378 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2381 memset(&m, 0, sizeof(m));
2382 m.tex[0] = R_GetTexture(basetexture);
2383 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2384 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2385 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2386 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2387 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2388 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2389 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2390 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2391 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2392 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2394 else if (r_textureunits.integer >= 4)
2396 // 4/2 2D combine path (Geforce3, Radeon 8500)
2397 memset(&m, 0, sizeof(m));
2398 m.tex[0] = R_GetTexture(normalmaptexture);
2399 m.texcombinergb[0] = GL_REPLACE;
2400 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2401 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2402 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2403 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2404 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2405 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2406 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2407 m.pointer_texcoord_bufferobject[1] = 0;
2408 m.pointer_texcoord_bufferoffset[1] = 0;
2409 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2410 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2411 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2412 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2413 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2414 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2415 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2416 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2417 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2418 m.texmatrix[3] = rsurface.entitytoattenuationz;
2419 R_Mesh_TextureState(&m);
2420 GL_ColorMask(0,0,0,1);
2421 GL_BlendFunc(GL_ONE, GL_ZERO);
2422 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2425 memset(&m, 0, sizeof(m));
2426 m.tex[0] = R_GetTexture(basetexture);
2427 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2428 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2429 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2430 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2431 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2433 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2434 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2435 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2436 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2437 m.texmatrix[1] = rsurface.entitytolight;
2439 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2443 // 2/2/2 2D combine path (any dot3 card)
2444 memset(&m, 0, sizeof(m));
2445 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2446 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2447 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2448 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2449 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2450 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2451 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2452 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2453 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2454 m.texmatrix[1] = rsurface.entitytoattenuationz;
2455 R_Mesh_TextureState(&m);
2456 GL_ColorMask(0,0,0,1);
2457 GL_BlendFunc(GL_ONE, GL_ZERO);
2458 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2461 memset(&m, 0, sizeof(m));
2462 m.tex[0] = R_GetTexture(normalmaptexture);
2463 m.texcombinergb[0] = GL_REPLACE;
2464 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2465 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2466 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2467 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2468 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2469 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2470 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2471 m.pointer_texcoord_bufferobject[1] = 0;
2472 m.pointer_texcoord_bufferoffset[1] = 0;
2473 R_Mesh_TextureState(&m);
2474 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2475 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2478 memset(&m, 0, sizeof(m));
2479 m.tex[0] = R_GetTexture(basetexture);
2480 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2481 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2482 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2483 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2484 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2486 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2487 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2488 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2489 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2490 m.texmatrix[1] = rsurface.entitytolight;
2492 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2494 // this final code is shared
2495 R_Mesh_TextureState(&m);
2496 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);
2499 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)
2501 float glossexponent;
2503 // FIXME: detect blendsquare!
2504 //if (!gl_support_blendsquare)
2507 // generate normalization cubemap texcoords
2508 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2509 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2511 // 2/0/0/1/2 3D combine blendsquare path
2512 memset(&m, 0, sizeof(m));
2513 m.tex[0] = R_GetTexture(normalmaptexture);
2514 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2515 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2516 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2517 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2518 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2519 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2520 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2521 m.pointer_texcoord_bufferobject[1] = 0;
2522 m.pointer_texcoord_bufferoffset[1] = 0;
2523 R_Mesh_TextureState(&m);
2524 GL_ColorMask(0,0,0,1);
2525 // this squares the result
2526 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2527 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2529 // second and third pass
2530 R_Mesh_ResetTextureState();
2531 // square alpha in framebuffer a few times to make it shiny
2532 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2533 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2534 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2537 memset(&m, 0, sizeof(m));
2538 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2539 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2540 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2541 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2542 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2543 R_Mesh_TextureState(&m);
2544 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2545 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2548 memset(&m, 0, sizeof(m));
2549 m.tex[0] = R_GetTexture(glosstexture);
2550 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2551 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2552 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2553 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2554 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2556 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2557 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2558 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2559 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2560 m.texmatrix[1] = rsurface.entitytolight;
2562 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2564 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2566 // 2/0/0/2 3D combine blendsquare path
2567 memset(&m, 0, sizeof(m));
2568 m.tex[0] = R_GetTexture(normalmaptexture);
2569 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2570 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2571 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2572 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2573 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2574 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2575 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2576 m.pointer_texcoord_bufferobject[1] = 0;
2577 m.pointer_texcoord_bufferoffset[1] = 0;
2578 R_Mesh_TextureState(&m);
2579 GL_ColorMask(0,0,0,1);
2580 // this squares the result
2581 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2582 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2584 // second and third pass
2585 R_Mesh_ResetTextureState();
2586 // square alpha in framebuffer a few times to make it shiny
2587 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2588 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2589 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2592 memset(&m, 0, sizeof(m));
2593 m.tex[0] = R_GetTexture(glosstexture);
2594 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2595 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2596 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2597 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2598 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2599 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2600 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2601 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2602 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2603 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2607 // 2/0/0/2/2 2D combine blendsquare path
2608 memset(&m, 0, sizeof(m));
2609 m.tex[0] = R_GetTexture(normalmaptexture);
2610 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2611 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2612 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2613 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2614 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2615 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2616 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2617 m.pointer_texcoord_bufferobject[1] = 0;
2618 m.pointer_texcoord_bufferoffset[1] = 0;
2619 R_Mesh_TextureState(&m);
2620 GL_ColorMask(0,0,0,1);
2621 // this squares the result
2622 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2623 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2625 // second and third pass
2626 R_Mesh_ResetTextureState();
2627 // square alpha in framebuffer a few times to make it shiny
2628 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2629 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2630 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2633 memset(&m, 0, sizeof(m));
2634 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2635 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2636 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2637 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2638 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2639 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2640 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2641 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2642 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2643 m.texmatrix[1] = rsurface.entitytoattenuationz;
2644 R_Mesh_TextureState(&m);
2645 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2646 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2649 memset(&m, 0, sizeof(m));
2650 m.tex[0] = R_GetTexture(glosstexture);
2651 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2652 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2653 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2654 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2655 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2657 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2658 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2659 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2660 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2661 m.texmatrix[1] = rsurface.entitytolight;
2663 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2665 // this final code is shared
2666 R_Mesh_TextureState(&m);
2667 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);
2670 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)
2672 // ARB path (any Geforce, any Radeon)
2673 qboolean doambient = ambientscale > 0;
2674 qboolean dodiffuse = diffusescale > 0;
2675 qboolean dospecular = specularscale > 0;
2676 if (!doambient && !dodiffuse && !dospecular)
2678 R_Mesh_ColorPointer(NULL, 0, 0);
2680 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2682 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2686 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2688 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2693 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2695 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2698 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2701 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2708 int newnumtriangles;
2712 int maxtriangles = 4096;
2713 int newelements[4096*3];
2714 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2715 for (renders = 0;renders < 64;renders++)
2720 newnumtriangles = 0;
2722 // due to low fillrate on the cards this vertex lighting path is
2723 // designed for, we manually cull all triangles that do not
2724 // contain a lit vertex
2725 // this builds batches of triangles from multiple surfaces and
2726 // renders them at once
2727 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2729 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2731 if (newnumtriangles)
2733 newfirstvertex = min(newfirstvertex, e[0]);
2734 newlastvertex = max(newlastvertex, e[0]);
2738 newfirstvertex = e[0];
2739 newlastvertex = e[0];
2741 newfirstvertex = min(newfirstvertex, e[1]);
2742 newlastvertex = max(newlastvertex, e[1]);
2743 newfirstvertex = min(newfirstvertex, e[2]);
2744 newlastvertex = max(newlastvertex, e[2]);
2750 if (newnumtriangles >= maxtriangles)
2752 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2753 newnumtriangles = 0;
2759 if (newnumtriangles >= 1)
2761 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2764 // if we couldn't find any lit triangles, exit early
2767 // now reduce the intensity for the next overbright pass
2768 // we have to clamp to 0 here incase the drivers have improper
2769 // handling of negative colors
2770 // (some old drivers even have improper handling of >1 color)
2772 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2774 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2776 c[0] = max(0, c[0] - 1);
2777 c[1] = max(0, c[1] - 1);
2778 c[2] = max(0, c[2] - 1);
2790 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)
2792 // OpenGL 1.1 path (anything)
2793 float ambientcolorbase[3], diffusecolorbase[3];
2794 float ambientcolorpants[3], diffusecolorpants[3];
2795 float ambientcolorshirt[3], diffusecolorshirt[3];
2797 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2798 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2799 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2800 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2801 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2802 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2803 memset(&m, 0, sizeof(m));
2804 m.tex[0] = R_GetTexture(basetexture);
2805 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2806 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2807 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2808 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2809 if (r_textureunits.integer >= 2)
2812 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2813 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2814 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2815 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2816 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2817 if (r_textureunits.integer >= 3)
2819 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2820 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2821 m.texmatrix[2] = rsurface.entitytoattenuationz;
2822 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2823 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2824 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2827 R_Mesh_TextureState(&m);
2828 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2829 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2832 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2833 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2837 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2838 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2842 extern cvar_t gl_lightmaps;
2843 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)
2845 float ambientscale, diffusescale, specularscale;
2846 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2848 // calculate colors to render this texture with
2849 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2850 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2851 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2852 ambientscale = rsurface.rtlight->ambientscale;
2853 diffusescale = rsurface.rtlight->diffusescale;
2854 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2855 if (!r_shadow_usenormalmap.integer)
2857 ambientscale += 1.0f * diffusescale;
2861 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2863 RSurf_SetupDepthAndCulling();
2864 nmap = rsurface.texture->currentskinframe->nmap;
2865 if (gl_lightmaps.integer)
2866 nmap = r_texture_blanknormalmap;
2867 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2869 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2870 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2873 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2874 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2875 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2878 VectorClear(lightcolorpants);
2881 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2882 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2883 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2886 VectorClear(lightcolorshirt);
2887 switch (r_shadow_rendermode)
2889 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2890 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2891 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);
2893 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2894 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);
2896 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2897 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);
2899 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2900 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);
2903 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2909 switch (r_shadow_rendermode)
2911 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2912 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2913 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2915 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2916 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);
2918 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2919 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);
2921 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2922 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);
2925 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2931 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)
2933 matrix4x4_t tempmatrix = *matrix;
2934 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2936 // if this light has been compiled before, free the associated data
2937 R_RTLight_Uncompile(rtlight);
2939 // clear it completely to avoid any lingering data
2940 memset(rtlight, 0, sizeof(*rtlight));
2942 // copy the properties
2943 rtlight->matrix_lighttoworld = tempmatrix;
2944 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2945 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2946 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2947 VectorCopy(color, rtlight->color);
2948 rtlight->cubemapname[0] = 0;
2949 if (cubemapname && cubemapname[0])
2950 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2951 rtlight->shadow = shadow;
2952 rtlight->corona = corona;
2953 rtlight->style = style;
2954 rtlight->isstatic = isstatic;
2955 rtlight->coronasizescale = coronasizescale;
2956 rtlight->ambientscale = ambientscale;
2957 rtlight->diffusescale = diffusescale;
2958 rtlight->specularscale = specularscale;
2959 rtlight->flags = flags;
2961 // compute derived data
2962 //rtlight->cullradius = rtlight->radius;
2963 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2964 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2965 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2966 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2967 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2968 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2969 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2972 // compiles rtlight geometry
2973 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2974 void R_RTLight_Compile(rtlight_t *rtlight)
2977 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2978 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2979 entity_render_t *ent = r_refdef.scene.worldentity;
2980 dp_model_t *model = r_refdef.scene.worldmodel;
2981 unsigned char *data;
2984 // compile the light
2985 rtlight->compiled = true;
2986 rtlight->static_numleafs = 0;
2987 rtlight->static_numleafpvsbytes = 0;
2988 rtlight->static_leaflist = NULL;
2989 rtlight->static_leafpvs = NULL;
2990 rtlight->static_numsurfaces = 0;
2991 rtlight->static_surfacelist = NULL;
2992 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2993 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2994 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2995 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2996 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2997 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2999 if (model && model->GetLightInfo)
3001 // this variable must be set for the CompileShadowVolume code
3002 r_shadow_compilingrtlight = rtlight;
3003 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);
3004 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);
3005 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3006 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3007 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3008 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3009 rtlight->static_numsurfaces = numsurfaces;
3010 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3011 rtlight->static_numleafs = numleafs;
3012 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3013 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3014 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3015 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3016 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3017 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3018 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3019 if (rtlight->static_numsurfaces)
3020 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3021 if (rtlight->static_numleafs)
3022 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3023 if (rtlight->static_numleafpvsbytes)
3024 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3025 if (rtlight->static_numshadowtrispvsbytes)
3026 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3027 if (rtlight->static_numlighttrispvsbytes)
3028 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3029 if (model->CompileShadowVolume && rtlight->shadow)
3030 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3031 // now we're done compiling the rtlight
3032 r_shadow_compilingrtlight = NULL;
3036 // use smallest available cullradius - box radius or light radius
3037 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3038 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3040 shadowzpasstris = 0;
3041 if (rtlight->static_meshchain_shadow_zpass)
3042 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3043 shadowzpasstris += mesh->numtriangles;
3045 shadowzfailtris = 0;
3046 if (rtlight->static_meshchain_shadow_zfail)
3047 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3048 shadowzfailtris += mesh->numtriangles;
3051 if (rtlight->static_numlighttrispvsbytes)
3052 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3053 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3057 if (rtlight->static_numlighttrispvsbytes)
3058 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3059 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3062 if (developer.integer >= 10)
3063 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);
3066 void R_RTLight_Uncompile(rtlight_t *rtlight)
3068 if (rtlight->compiled)
3070 if (rtlight->static_meshchain_shadow_zpass)
3071 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3072 rtlight->static_meshchain_shadow_zpass = NULL;
3073 if (rtlight->static_meshchain_shadow_zfail)
3074 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3075 rtlight->static_meshchain_shadow_zfail = NULL;
3076 // these allocations are grouped
3077 if (rtlight->static_surfacelist)
3078 Mem_Free(rtlight->static_surfacelist);
3079 rtlight->static_numleafs = 0;
3080 rtlight->static_numleafpvsbytes = 0;
3081 rtlight->static_leaflist = NULL;
3082 rtlight->static_leafpvs = NULL;
3083 rtlight->static_numsurfaces = 0;
3084 rtlight->static_surfacelist = NULL;
3085 rtlight->static_numshadowtrispvsbytes = 0;
3086 rtlight->static_shadowtrispvs = NULL;
3087 rtlight->static_numlighttrispvsbytes = 0;
3088 rtlight->static_lighttrispvs = NULL;
3089 rtlight->compiled = false;
3093 void R_Shadow_UncompileWorldLights(void)
3097 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3098 for (lightindex = 0;lightindex < range;lightindex++)
3100 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3103 R_RTLight_Uncompile(&light->rtlight);
3107 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3111 // reset the count of frustum planes
3112 // see rsurface.rtlight_frustumplanes definition for how much this array
3114 rsurface.rtlight_numfrustumplanes = 0;
3116 // haven't implemented a culling path for ortho rendering
3117 if (!r_refdef.view.useperspective)
3119 // check if the light is on screen and copy the 4 planes if it is
3120 for (i = 0;i < 4;i++)
3121 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3124 for (i = 0;i < 4;i++)
3125 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3130 // generate a deformed frustum that includes the light origin, this is
3131 // used to cull shadow casting surfaces that can not possibly cast a
3132 // shadow onto the visible light-receiving surfaces, which can be a
3135 // if the light origin is onscreen the result will be 4 planes exactly
3136 // if the light origin is offscreen on only one axis the result will
3137 // be exactly 5 planes (split-side case)
3138 // if the light origin is offscreen on two axes the result will be
3139 // exactly 4 planes (stretched corner case)
3140 for (i = 0;i < 4;i++)
3142 // quickly reject standard frustum planes that put the light
3143 // origin outside the frustum
3144 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3147 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3149 // if all the standard frustum planes were accepted, the light is onscreen
3150 // otherwise we need to generate some more planes below...
3151 if (rsurface.rtlight_numfrustumplanes < 4)
3153 // at least one of the stock frustum planes failed, so we need to
3154 // create one or two custom planes to enclose the light origin
3155 for (i = 0;i < 4;i++)
3157 // create a plane using the view origin and light origin, and a
3158 // single point from the frustum corner set
3159 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3160 VectorNormalize(plane.normal);
3161 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3162 // see if this plane is backwards and flip it if so
3163 for (j = 0;j < 4;j++)
3164 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3168 VectorNegate(plane.normal, plane.normal);
3170 // flipped plane, test again to see if it is now valid
3171 for (j = 0;j < 4;j++)
3172 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3174 // if the plane is still not valid, then it is dividing the
3175 // frustum and has to be rejected
3179 // we have created a valid plane, compute extra info
3180 PlaneClassify(&plane);
3182 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3184 // if we've found 5 frustum planes then we have constructed a
3185 // proper split-side case and do not need to keep searching for
3186 // planes to enclose the light origin
3187 if (rsurface.rtlight_numfrustumplanes == 5)
3195 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3197 plane = rsurface.rtlight_frustumplanes[i];
3198 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));
3203 // now add the light-space box planes if the light box is rotated, as any
3204 // caster outside the oriented light box is irrelevant (even if it passed
3205 // the worldspace light box, which is axial)
3206 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3208 for (i = 0;i < 6;i++)
3212 v[i >> 1] = (i & 1) ? -1 : 1;
3213 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3214 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3215 plane.dist = VectorNormalizeLength(plane.normal);
3216 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3217 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3223 // add the world-space reduced box planes
3224 for (i = 0;i < 6;i++)
3226 VectorClear(plane.normal);
3227 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3228 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3229 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3238 // reduce all plane distances to tightly fit the rtlight cull box, which
3240 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3241 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3242 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3243 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3244 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3245 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3246 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3247 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3248 oldnum = rsurface.rtlight_numfrustumplanes;
3249 rsurface.rtlight_numfrustumplanes = 0;
3250 for (j = 0;j < oldnum;j++)
3252 // find the nearest point on the box to this plane
3253 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3254 for (i = 1;i < 8;i++)
3256 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3257 if (bestdist > dist)
3260 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);
3261 // if the nearest point is near or behind the plane, we want this
3262 // plane, otherwise the plane is useless as it won't cull anything
3263 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3265 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3266 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3273 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3278 int surfacelistindex;
3279 msurface_t *surface;
3281 RSurf_ActiveWorldEntity();
3282 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3284 if (r_refdef.scene.worldentity->model)
3285 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3286 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3290 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3293 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3294 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3295 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3296 for (;mesh;mesh = mesh->next)
3298 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3299 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3300 GL_LockArrays(0, mesh->numverts);
3301 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3303 // increment stencil if frontface is infront of depthbuffer
3304 GL_CullFace(r_refdef.view.cullface_back);
3305 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3306 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3307 // decrement stencil if backface is infront of depthbuffer
3308 GL_CullFace(r_refdef.view.cullface_front);
3309 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3311 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3313 // decrement stencil if backface is behind depthbuffer
3314 GL_CullFace(r_refdef.view.cullface_front);
3315 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3316 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3317 // increment stencil if frontface is behind depthbuffer
3318 GL_CullFace(r_refdef.view.cullface_back);
3319 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3321 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3322 GL_LockArrays(0, 0);
3326 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3328 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3329 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3331 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3332 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3333 if (CHECKPVSBIT(trispvs, t))
3334 shadowmarklist[numshadowmark++] = t;
3336 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);
3338 else if (numsurfaces)
3339 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3341 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3344 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3346 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3347 vec_t relativeshadowradius;
3348 RSurf_ActiveModelEntity(ent, false, false);
3349 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3350 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3351 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3352 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3353 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3354 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3355 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3356 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3357 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3358 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3360 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3361 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3364 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3366 // set up properties for rendering light onto this entity
3367 RSurf_ActiveModelEntity(ent, true, true);
3368 GL_AlphaTest(false);
3369 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3370 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3371 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3372 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3373 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3374 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3377 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3379 if (!r_refdef.scene.worldmodel->DrawLight)
3382 // set up properties for rendering light onto this entity
3383 RSurf_ActiveWorldEntity();
3384 GL_AlphaTest(false);
3385 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3386 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3387 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3388 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3389 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3390 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3392 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3394 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3397 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3399 dp_model_t *model = ent->model;
3400 if (!model->DrawLight)
3403 R_Shadow_SetupEntityLight(ent);
3405 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3411 {{ 0, 0, 0}, "px", true, true, true},
3412 {{ 0, 90, 0}, "py", false, true, false},
3413 {{ 0, 180, 0}, "nx", false, false, true},
3414 {{ 0, 270, 0}, "ny", true, false, false},
3415 {{-90, 180, 0}, "pz", false, false, true},
3416 {{ 90, 180, 0}, "nz", false, false, true}
3419 static const double shadowviewmat16[6][4][4] =
3459 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3463 int numleafs, numsurfaces;
3464 int *leaflist, *surfacelist;
3465 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3466 int numlightentities;
3467 int numlightentities_noselfshadow;
3468 int numshadowentities;
3469 int numshadowentities_noselfshadow;
3470 static entity_render_t *lightentities[MAX_EDICTS];
3471 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3472 static entity_render_t *shadowentities[MAX_EDICTS];
3473 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3474 vec3_t nearestpoint;
3476 qboolean castshadows;
3479 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3480 // skip lights that are basically invisible (color 0 0 0)
3481 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3484 // loading is done before visibility checks because loading should happen
3485 // all at once at the start of a level, not when it stalls gameplay.
3486 // (especially important to benchmarks)
3488 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3489 R_RTLight_Compile(rtlight);
3491 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3493 // look up the light style value at this time
3494 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3495 VectorScale(rtlight->color, f, rtlight->currentcolor);
3497 if (rtlight->selected)
3499 f = 2 + sin(realtime * M_PI * 4.0);
3500 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3504 // if lightstyle is currently off, don't draw the light
3505 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3508 // if the light box is offscreen, skip it
3509 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3512 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3513 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3515 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3517 // compiled light, world available and can receive realtime lighting
3518 // retrieve leaf information
3519 numleafs = rtlight->static_numleafs;
3520 leaflist = rtlight->static_leaflist;
3521 leafpvs = rtlight->static_leafpvs;
3522 numsurfaces = rtlight->static_numsurfaces;
3523 surfacelist = rtlight->static_surfacelist;
3524 shadowtrispvs = rtlight->static_shadowtrispvs;
3525 lighttrispvs = rtlight->static_lighttrispvs;
3527 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3529 // dynamic light, world available and can receive realtime lighting
3530 // calculate lit surfaces and leafs
3531 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);
3532 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);
3533 leaflist = r_shadow_buffer_leaflist;
3534 leafpvs = r_shadow_buffer_leafpvs;
3535 surfacelist = r_shadow_buffer_surfacelist;
3536 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3537 lighttrispvs = r_shadow_buffer_lighttrispvs;
3538 // if the reduced leaf bounds are offscreen, skip it
3539 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3550 shadowtrispvs = NULL;
3551 lighttrispvs = NULL;
3553 // check if light is illuminating any visible leafs
3556 for (i = 0;i < numleafs;i++)
3557 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3562 // set up a scissor rectangle for this light
3563 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3566 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3568 // make a list of lit entities and shadow casting entities
3569 numlightentities = 0;
3570 numlightentities_noselfshadow = 0;
3571 numshadowentities = 0;
3572 numshadowentities_noselfshadow = 0;
3573 // add dynamic entities that are lit by the light
3574 if (r_drawentities.integer)
3576 for (i = 0;i < r_refdef.scene.numentities;i++)
3579 entity_render_t *ent = r_refdef.scene.entities[i];
3581 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3583 // skip the object entirely if it is not within the valid
3584 // shadow-casting region (which includes the lit region)
3585 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3587 if (!(model = ent->model))
3589 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3591 // this entity wants to receive light, is visible, and is
3592 // inside the light box
3593 // TODO: check if the surfaces in the model can receive light
3594 // so now check if it's in a leaf seen by the light
3595 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))
3597 if (ent->flags & RENDER_NOSELFSHADOW)
3598 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3600 lightentities[numlightentities++] = ent;
3601 // since it is lit, it probably also casts a shadow...
3602 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3603 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3604 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3606 // note: exterior models without the RENDER_NOSELFSHADOW
3607 // flag still create a RENDER_NOSELFSHADOW shadow but
3608 // are lit normally, this means that they are
3609 // self-shadowing but do not shadow other
3610 // RENDER_NOSELFSHADOW entities such as the gun
3611 // (very weird, but keeps the player shadow off the gun)
3612 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3613 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3615 shadowentities[numshadowentities++] = ent;
3618 else if (ent->flags & RENDER_SHADOW)
3620 // this entity is not receiving light, but may still need to
3622 // TODO: check if the surfaces in the model can cast shadow
3623 // now check if it is in a leaf seen by the light
3624 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))
3626 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3627 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3628 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3630 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3631 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3633 shadowentities[numshadowentities++] = ent;
3639 // return if there's nothing at all to light
3640 if (!numlightentities && !numsurfaces)
3643 // don't let sound skip if going slow
3644 if (r_refdef.scene.extraupdate)
3647 // make this the active rtlight for rendering purposes
3648 R_Shadow_RenderMode_ActiveLight(rtlight);
3649 // count this light in the r_speeds
3650 r_refdef.stats.lights++;
3652 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3654 // optionally draw visible shape of the shadow volumes
3655 // for performance analysis by level designers
3656 R_Shadow_RenderMode_VisibleShadowVolumes();
3658 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3659 for (i = 0;i < numshadowentities;i++)
3660 R_Shadow_DrawEntityShadow(shadowentities[i]);
3661 for (i = 0;i < numshadowentities_noselfshadow;i++)
3662 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3665 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3667 // optionally draw the illuminated areas
3668 // for performance analysis by level designers
3669 R_Shadow_RenderMode_VisibleLighting(false, false);
3671 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3672 for (i = 0;i < numlightentities;i++)
3673 R_Shadow_DrawEntityLight(lightentities[i]);
3674 for (i = 0;i < numlightentities_noselfshadow;i++)
3675 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3678 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3680 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3681 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3682 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3683 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3684 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3685 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3687 if (castshadows && r_shadow_shadowmapping.integer >= 1 && r_shadow_shadowmapping.integer <= 3 && r_glsl.integer && gl_support_fragment_shader)
3692 r_shadow_shadowmaplod = 0;
3693 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3694 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3695 r_shadow_shadowmaplod = i;
3698 if (r_shadow_shadowmapping.integer == 3)
3699 size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod;
3700 size = bound(1, size, 2048);
3702 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3704 // render shadow casters into 6 sided depth texture
3705 for (side = 0;side < 6;side++)
3707 R_Shadow_RenderMode_ShadowMap(side, true, size);
3709 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3710 for (i = 0;i < numshadowentities;i++)
3711 R_Shadow_DrawEntityShadow(shadowentities[i]);
3714 if (numlightentities_noselfshadow)
3716 // render lighting using the depth texture as shadowmap
3717 // draw lighting in the unmasked areas
3718 R_Shadow_RenderMode_Lighting(false, false, true);
3719 for (i = 0;i < numlightentities_noselfshadow;i++)
3720 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3723 // render shadow casters into 6 sided depth texture
3724 for (side = 0;side < 6;side++)
3726 R_Shadow_RenderMode_ShadowMap(side, false, size);
3727 for (i = 0;i < numshadowentities_noselfshadow;i++)
3728 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3730 if (r_shadow_shadowmapping.integer == 1)
3732 int w = R_TextureWidth(r_shadow_shadowmap2dtexture);
3733 int h = R_TextureHeight(r_shadow_shadowmap2dtexture);
3734 static int once = true;
3737 unsigned char *blah = Z_Malloc(w*h*4);
3738 qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR
3739 FS_WriteFile("testshadowmap.bin", blah, w*h*4);
3747 // render lighting using the depth texture as shadowmap
3748 // draw lighting in the unmasked areas
3749 R_Shadow_RenderMode_Lighting(false, false, true);
3750 // draw lighting in the unmasked areas
3752 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3753 for (i = 0;i < numlightentities;i++)
3754 R_Shadow_DrawEntityLight(lightentities[i]);
3756 else if (castshadows && gl_stencil)
3758 // draw stencil shadow volumes to mask off pixels that are in shadow
3759 // so that they won't receive lighting
3760 R_Shadow_ClearStencil();
3762 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3763 for (i = 0;i < numshadowentities;i++)
3764 R_Shadow_DrawEntityShadow(shadowentities[i]);
3765 if (numlightentities_noselfshadow)
3767 // draw lighting in the unmasked areas
3768 R_Shadow_RenderMode_Lighting(true, false, false);
3769 for (i = 0;i < numlightentities_noselfshadow;i++)
3770 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3772 // optionally draw the illuminated areas
3773 // for performance analysis by level designers
3774 if (r_showlighting.integer && r_refdef.view.showdebug)
3776 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3777 for (i = 0;i < numlightentities_noselfshadow;i++)
3778 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3781 for (i = 0;i < numshadowentities_noselfshadow;i++)
3782 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3784 if (numsurfaces + numlightentities)
3786 // draw lighting in the unmasked areas
3787 R_Shadow_RenderMode_Lighting(true, false, false);
3789 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3790 for (i = 0;i < numlightentities;i++)
3791 R_Shadow_DrawEntityLight(lightentities[i]);
3796 if (numsurfaces + numlightentities)
3798 // draw lighting in the unmasked areas
3799 R_Shadow_RenderMode_Lighting(false, false, false);
3801 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3802 for (i = 0;i < numlightentities;i++)
3803 R_Shadow_DrawEntityLight(lightentities[i]);
3804 for (i = 0;i < numlightentities_noselfshadow;i++)
3805 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3810 void R_Shadow_DrawLightSprites(void);
3811 void R_ShadowVolumeLighting(qboolean visible)
3819 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) || r_shadow_shadowmode != r_shadow_shadowmapping.integer)
3820 R_Shadow_FreeShadowMaps();
3822 if (r_editlights.integer)
3823 R_Shadow_DrawLightSprites();
3825 R_Shadow_RenderMode_Begin();
3827 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3828 if (r_shadow_debuglight.integer >= 0)
3830 lightindex = r_shadow_debuglight.integer;
3831 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3832 if (light && (light->flags & flag))
3833 R_DrawRTLight(&light->rtlight, visible);
3837 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3838 for (lightindex = 0;lightindex < range;lightindex++)
3840 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3841 if (light && (light->flags & flag))
3842 R_DrawRTLight(&light->rtlight, visible);
3845 if (r_refdef.scene.rtdlight)
3846 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3847 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3849 R_Shadow_RenderMode_End();
3852 extern const float r_screenvertex3f[12];
3853 extern void R_SetupView(qboolean allowwaterclippingplane);
3854 extern void R_ResetViewRendering3D(void);
3855 extern void R_ResetViewRendering2D(void);
3856 extern cvar_t r_shadows;
3857 extern cvar_t r_shadows_darken;
3858 extern cvar_t r_shadows_drawafterrtlighting;
3859 extern cvar_t r_shadows_castfrombmodels;
3860 extern cvar_t r_shadows_throwdistance;
3861 extern cvar_t r_shadows_throwdirection;
3862 void R_DrawModelShadows(void)
3865 float relativethrowdistance;
3866 entity_render_t *ent;
3867 vec3_t relativelightorigin;
3868 vec3_t relativelightdirection;
3869 vec3_t relativeshadowmins, relativeshadowmaxs;
3870 vec3_t tmp, shadowdir;
3872 if (!r_drawentities.integer || !gl_stencil)
3876 R_ResetViewRendering3D();
3877 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3878 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3879 R_Shadow_RenderMode_Begin();
3880 R_Shadow_RenderMode_ActiveLight(NULL);
3881 r_shadow_lightscissor[0] = r_refdef.view.x;
3882 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3883 r_shadow_lightscissor[2] = r_refdef.view.width;
3884 r_shadow_lightscissor[3] = r_refdef.view.height;
3885 R_Shadow_RenderMode_StencilShadowVolumes(false);
3888 if (r_shadows.integer == 2)
3890 Math_atov(r_shadows_throwdirection.string, shadowdir);
3891 VectorNormalize(shadowdir);
3894 R_Shadow_ClearStencil();
3896 for (i = 0;i < r_refdef.scene.numentities;i++)
3898 ent = r_refdef.scene.entities[i];
3900 // cast shadows from anything of the map (submodels are optional)
3901 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3903 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3904 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3905 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3906 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3907 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3910 if(ent->entitynumber != 0)
3912 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3913 int entnum, entnum2, recursion;
3914 entnum = entnum2 = ent->entitynumber;
3915 for(recursion = 32; recursion > 0; --recursion)
3917 entnum2 = cl.entities[entnum].state_current.tagentity;
3918 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3923 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3925 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3926 // transform into modelspace of OUR entity
3927 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3928 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3931 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3934 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3937 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3938 RSurf_ActiveModelEntity(ent, false, false);
3939 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3940 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3944 // not really the right mode, but this will disable any silly stencil features
3945 R_Shadow_RenderMode_End();
3947 // set up ortho view for rendering this pass
3948 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3949 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3950 //GL_ScissorTest(true);
3951 //R_Mesh_Matrix(&identitymatrix);
3952 //R_Mesh_ResetTextureState();
3953 R_ResetViewRendering2D();
3954 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3955 R_Mesh_ColorPointer(NULL, 0, 0);
3956 R_SetupGenericShader(false);
3958 // set up a darkening blend on shadowed areas
3959 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3960 //GL_DepthRange(0, 1);
3961 //GL_DepthTest(false);
3962 //GL_DepthMask(false);
3963 //GL_PolygonOffset(0, 0);CHECKGLERROR
3964 GL_Color(0, 0, 0, r_shadows_darken.value);
3965 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3966 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3967 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3968 qglStencilMask(~0);CHECKGLERROR
3969 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3970 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3972 // apply the blend to the shadowed areas
3973 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3975 // restore the viewport
3976 R_SetViewport(&r_refdef.view.viewport);
3978 // restore other state to normal
3979 //R_Shadow_RenderMode_End();
3982 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
3985 vec3_t centerorigin;
3986 // if it's too close, skip it
3987 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
3989 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
3992 if (usequery && r_numqueries + 2 <= r_maxqueries)
3994 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
3995 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
3996 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
3999 // 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
4000 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4001 qglDepthFunc(GL_ALWAYS);
4002 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);
4003 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4004 qglDepthFunc(GL_LEQUAL);
4005 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4006 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);
4007 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4010 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4013 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4016 GLint allpixels = 0, visiblepixels = 0;
4017 // now we have to check the query result
4018 if (rtlight->corona_queryindex_visiblepixels)
4021 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4022 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4024 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4025 if (visiblepixels < 1 || allpixels < 1)
4027 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4028 cscale *= rtlight->corona_visibility;
4032 // FIXME: these traces should scan all render entities instead of cl.world
4033 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4036 VectorScale(rtlight->color, cscale, color);
4037 if (VectorLength(color) > (1.0f / 256.0f))
4038 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);
4041 void R_DrawCoronas(void)
4049 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4051 if (r_waterstate.renderingscene)
4053 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4054 R_Mesh_Matrix(&identitymatrix);
4056 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4058 // check occlusion of coronas
4059 // use GL_ARB_occlusion_query if available
4060 // otherwise use raytraces
4062 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4065 GL_ColorMask(0,0,0,0);
4066 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4067 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4070 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4071 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4073 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4077 for (lightindex = 0;lightindex < range;lightindex++)
4079 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4082 rtlight = &light->rtlight;
4083 rtlight->corona_visibility = 0;
4084 rtlight->corona_queryindex_visiblepixels = 0;
4085 rtlight->corona_queryindex_allpixels = 0;
4086 if (!(rtlight->flags & flag))
4088 if (rtlight->corona <= 0)
4090 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4092 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4094 for (i = 0;i < r_refdef.scene.numlights;i++)
4096 rtlight = r_refdef.scene.lights[i];
4097 rtlight->corona_visibility = 0;
4098 rtlight->corona_queryindex_visiblepixels = 0;
4099 rtlight->corona_queryindex_allpixels = 0;
4100 if (!(rtlight->flags & flag))
4102 if (rtlight->corona <= 0)
4104 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4107 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4109 // now draw the coronas using the query data for intensity info
4110 for (lightindex = 0;lightindex < range;lightindex++)
4112 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4115 rtlight = &light->rtlight;
4116 if (rtlight->corona_visibility <= 0)
4118 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4120 for (i = 0;i < r_refdef.scene.numlights;i++)
4122 rtlight = r_refdef.scene.lights[i];
4123 if (rtlight->corona_visibility <= 0)
4125 if (gl_flashblend.integer)
4126 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4128 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4134 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4135 typedef struct suffixinfo_s
4138 qboolean flipx, flipy, flipdiagonal;
4141 static suffixinfo_t suffix[3][6] =
4144 {"px", false, false, false},
4145 {"nx", false, false, false},
4146 {"py", false, false, false},
4147 {"ny", false, false, false},
4148 {"pz", false, false, false},
4149 {"nz", false, false, false}
4152 {"posx", false, false, false},
4153 {"negx", false, false, false},
4154 {"posy", false, false, false},
4155 {"negy", false, false, false},
4156 {"posz", false, false, false},
4157 {"negz", false, false, false}
4160 {"rt", true, false, true},
4161 {"lf", false, true, true},
4162 {"ft", true, true, false},
4163 {"bk", false, false, false},
4164 {"up", true, false, true},
4165 {"dn", true, false, true}
4169 static int componentorder[4] = {0, 1, 2, 3};
4171 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4173 int i, j, cubemapsize;
4174 unsigned char *cubemappixels, *image_buffer;
4175 rtexture_t *cubemaptexture;
4177 // must start 0 so the first loadimagepixels has no requested width/height
4179 cubemappixels = NULL;
4180 cubemaptexture = NULL;
4181 // keep trying different suffix groups (posx, px, rt) until one loads
4182 for (j = 0;j < 3 && !cubemappixels;j++)
4184 // load the 6 images in the suffix group
4185 for (i = 0;i < 6;i++)
4187 // generate an image name based on the base and and suffix
4188 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4190 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4192 // an image loaded, make sure width and height are equal
4193 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4195 // if this is the first image to load successfully, allocate the cubemap memory
4196 if (!cubemappixels && image_width >= 1)
4198 cubemapsize = image_width;
4199 // note this clears to black, so unavailable sides are black
4200 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4202 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4204 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);
4207 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4209 Mem_Free(image_buffer);
4213 // if a cubemap loaded, upload it
4216 if (developer_loading.integer)
4217 Con_Printf("loading cubemap \"%s\"\n", basename);
4219 if (!r_shadow_filters_texturepool)
4220 r_shadow_filters_texturepool = R_AllocTexturePool();
4221 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4222 Mem_Free(cubemappixels);
4226 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4227 if (developer_loading.integer)
4229 Con_Printf("(tried tried images ");
4230 for (j = 0;j < 3;j++)
4231 for (i = 0;i < 6;i++)
4232 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4233 Con_Print(" and was unable to find any of them).\n");
4236 return cubemaptexture;
4239 rtexture_t *R_Shadow_Cubemap(const char *basename)
4242 for (i = 0;i < numcubemaps;i++)
4243 if (!strcasecmp(cubemaps[i].basename, basename))
4244 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4245 if (i >= MAX_CUBEMAPS)
4246 return r_texture_whitecube;
4248 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4249 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4250 return cubemaps[i].texture;
4253 void R_Shadow_FreeCubemaps(void)
4256 for (i = 0;i < numcubemaps;i++)
4258 if (developer_loading.integer)
4259 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4260 if (cubemaps[i].texture)
4261 R_FreeTexture(cubemaps[i].texture);
4265 R_FreeTexturePool(&r_shadow_filters_texturepool);
4268 dlight_t *R_Shadow_NewWorldLight(void)
4270 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4273 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)
4276 // validate parameters
4277 if (style < 0 || style >= MAX_LIGHTSTYLES)
4279 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4285 // copy to light properties
4286 VectorCopy(origin, light->origin);
4287 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4288 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4289 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4290 light->color[0] = max(color[0], 0);
4291 light->color[1] = max(color[1], 0);
4292 light->color[2] = max(color[2], 0);
4293 light->radius = max(radius, 0);
4294 light->style = style;
4295 light->shadow = shadowenable;
4296 light->corona = corona;
4297 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4298 light->coronasizescale = coronasizescale;
4299 light->ambientscale = ambientscale;
4300 light->diffusescale = diffusescale;
4301 light->specularscale = specularscale;
4302 light->flags = flags;
4304 // update renderable light data
4305 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4306 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);
4309 void R_Shadow_FreeWorldLight(dlight_t *light)
4311 if (r_shadow_selectedlight == light)
4312 r_shadow_selectedlight = NULL;
4313 R_RTLight_Uncompile(&light->rtlight);
4314 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4317 void R_Shadow_ClearWorldLights(void)
4321 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4322 for (lightindex = 0;lightindex < range;lightindex++)
4324 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4326 R_Shadow_FreeWorldLight(light);
4328 r_shadow_selectedlight = NULL;
4329 R_Shadow_FreeCubemaps();
4332 void R_Shadow_SelectLight(dlight_t *light)
4334 if (r_shadow_selectedlight)
4335 r_shadow_selectedlight->selected = false;
4336 r_shadow_selectedlight = light;
4337 if (r_shadow_selectedlight)
4338 r_shadow_selectedlight->selected = true;
4341 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4343 // this is never batched (there can be only one)
4344 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);
4347 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4354 // this is never batched (due to the ent parameter changing every time)
4355 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4356 const dlight_t *light = (dlight_t *)ent;
4359 VectorScale(light->color, intensity, spritecolor);
4360 if (VectorLength(spritecolor) < 0.1732f)
4361 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4362 if (VectorLength(spritecolor) > 1.0f)
4363 VectorNormalize(spritecolor);
4365 // draw light sprite
4366 if (light->cubemapname[0] && !light->shadow)
4367 pic = r_editlights_sprcubemapnoshadowlight;
4368 else if (light->cubemapname[0])
4369 pic = r_editlights_sprcubemaplight;
4370 else if (!light->shadow)
4371 pic = r_editlights_sprnoshadowlight;
4373 pic = r_editlights_sprlight;
4374 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);
4375 // draw selection sprite if light is selected
4376 if (light->selected)
4377 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);
4378 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4381 void R_Shadow_DrawLightSprites(void)
4385 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4386 for (lightindex = 0;lightindex < range;lightindex++)
4388 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4390 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4392 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4395 void R_Shadow_SelectLightInView(void)
4397 float bestrating, rating, temp[3];
4401 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4404 for (lightindex = 0;lightindex < range;lightindex++)
4406 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4409 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4410 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4413 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4414 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)
4416 bestrating = rating;
4421 R_Shadow_SelectLight(best);
4424 void R_Shadow_LoadWorldLights(void)
4426 int n, a, style, shadow, flags;
4427 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4428 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4429 if (cl.worldmodel == NULL)
4431 Con_Print("No map loaded.\n");
4434 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4435 strlcat (name, ".rtlights", sizeof (name));
4436 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4446 for (;COM_Parse(t, true) && strcmp(
4447 if (COM_Parse(t, true))
4449 if (com_token[0] == '!')
4452 origin[0] = atof(com_token+1);
4455 origin[0] = atof(com_token);
4460 while (*s && *s != '\n' && *s != '\r')
4466 // check for modifier flags
4473 #if _MSC_VER >= 1400
4474 #define sscanf sscanf_s
4476 cubemapname[sizeof(cubemapname)-1] = 0;
4477 #if MAX_QPATH != 128
4478 #error update this code if MAX_QPATH changes
4480 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
4481 #if _MSC_VER >= 1400
4482 , sizeof(cubemapname)
4484 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4487 flags = LIGHTFLAG_REALTIMEMODE;
4495 coronasizescale = 0.25f;
4497 VectorClear(angles);
4500 if (a < 9 || !strcmp(cubemapname, "\"\""))
4502 // remove quotes on cubemapname
4503 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4506 namelen = strlen(cubemapname) - 2;
4507 memmove(cubemapname, cubemapname + 1, namelen);
4508 cubemapname[namelen] = '\0';
4512 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);
4515 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4523 Con_Printf("invalid rtlights file \"%s\"\n", name);
4524 Mem_Free(lightsstring);
4528 void R_Shadow_SaveWorldLights(void)
4532 size_t bufchars, bufmaxchars;
4534 char name[MAX_QPATH];
4535 char line[MAX_INPUTLINE];
4536 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4537 // I hate lines which are 3 times my screen size :( --blub
4540 if (cl.worldmodel == NULL)
4542 Con_Print("No map loaded.\n");
4545 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4546 strlcat (name, ".rtlights", sizeof (name));
4547 bufchars = bufmaxchars = 0;
4549 for (lightindex = 0;lightindex < range;lightindex++)
4551 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4554 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4555 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);
4556 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4557 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]);
4559 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);
4560 if (bufchars + strlen(line) > bufmaxchars)
4562 bufmaxchars = bufchars + strlen(line) + 2048;
4564 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4568 memcpy(buf, oldbuf, bufchars);
4574 memcpy(buf + bufchars, line, strlen(line));
4575 bufchars += strlen(line);
4579 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4584 void R_Shadow_LoadLightsFile(void)
4587 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4588 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4589 if (cl.worldmodel == NULL)
4591 Con_Print("No map loaded.\n");
4594 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4595 strlcat (name, ".lights", sizeof (name));
4596 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4604 while (*s && *s != '\n' && *s != '\r')
4610 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);
4614 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);
4617 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4618 radius = bound(15, radius, 4096);
4619 VectorScale(color, (2.0f / (8388608.0f)), color);
4620 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4628 Con_Printf("invalid lights file \"%s\"\n", name);
4629 Mem_Free(lightsstring);
4633 // tyrlite/hmap2 light types in the delay field
4634 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4636 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4638 int entnum, style, islight, skin, pflags, effects, type, n;
4641 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4642 char key[256], value[MAX_INPUTLINE];
4644 if (cl.worldmodel == NULL)
4646 Con_Print("No map loaded.\n");
4649 // try to load a .ent file first
4650 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4651 strlcat (key, ".ent", sizeof (key));
4652 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4653 // and if that is not found, fall back to the bsp file entity string
4655 data = cl.worldmodel->brush.entities;
4658 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4660 type = LIGHTTYPE_MINUSX;
4661 origin[0] = origin[1] = origin[2] = 0;
4662 originhack[0] = originhack[1] = originhack[2] = 0;
4663 angles[0] = angles[1] = angles[2] = 0;
4664 color[0] = color[1] = color[2] = 1;
4665 light[0] = light[1] = light[2] = 1;light[3] = 300;
4666 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4676 if (!COM_ParseToken_Simple(&data, false, false))
4678 if (com_token[0] == '}')
4679 break; // end of entity
4680 if (com_token[0] == '_')
4681 strlcpy(key, com_token + 1, sizeof(key));
4683 strlcpy(key, com_token, sizeof(key));
4684 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4685 key[strlen(key)-1] = 0;
4686 if (!COM_ParseToken_Simple(&data, false, false))
4688 strlcpy(value, com_token, sizeof(value));
4690 // now that we have the key pair worked out...
4691 if (!strcmp("light", key))
4693 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4697 light[0] = vec[0] * (1.0f / 256.0f);
4698 light[1] = vec[0] * (1.0f / 256.0f);
4699 light[2] = vec[0] * (1.0f / 256.0f);
4705 light[0] = vec[0] * (1.0f / 255.0f);
4706 light[1] = vec[1] * (1.0f / 255.0f);
4707 light[2] = vec[2] * (1.0f / 255.0f);
4711 else if (!strcmp("delay", key))
4713 else if (!strcmp("origin", key))
4714 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4715 else if (!strcmp("angle", key))
4716 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4717 else if (!strcmp("angles", key))
4718 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4719 else if (!strcmp("color", key))
4720 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4721 else if (!strcmp("wait", key))
4722 fadescale = atof(value);
4723 else if (!strcmp("classname", key))
4725 if (!strncmp(value, "light", 5))
4728 if (!strcmp(value, "light_fluoro"))
4733 overridecolor[0] = 1;
4734 overridecolor[1] = 1;
4735 overridecolor[2] = 1;
4737 if (!strcmp(value, "light_fluorospark"))
4742 overridecolor[0] = 1;
4743 overridecolor[1] = 1;
4744 overridecolor[2] = 1;
4746 if (!strcmp(value, "light_globe"))
4751 overridecolor[0] = 1;
4752 overridecolor[1] = 0.8;
4753 overridecolor[2] = 0.4;
4755 if (!strcmp(value, "light_flame_large_yellow"))
4760 overridecolor[0] = 1;
4761 overridecolor[1] = 0.5;
4762 overridecolor[2] = 0.1;
4764 if (!strcmp(value, "light_flame_small_yellow"))
4769 overridecolor[0] = 1;
4770 overridecolor[1] = 0.5;
4771 overridecolor[2] = 0.1;
4773 if (!strcmp(value, "light_torch_small_white"))
4778 overridecolor[0] = 1;
4779 overridecolor[1] = 0.5;
4780 overridecolor[2] = 0.1;
4782 if (!strcmp(value, "light_torch_small_walltorch"))
4787 overridecolor[0] = 1;
4788 overridecolor[1] = 0.5;
4789 overridecolor[2] = 0.1;
4793 else if (!strcmp("style", key))
4794 style = atoi(value);
4795 else if (!strcmp("skin", key))
4796 skin = (int)atof(value);
4797 else if (!strcmp("pflags", key))
4798 pflags = (int)atof(value);
4799 else if (!strcmp("effects", key))
4800 effects = (int)atof(value);
4801 else if (cl.worldmodel->type == mod_brushq3)
4803 if (!strcmp("scale", key))
4804 lightscale = atof(value);
4805 if (!strcmp("fade", key))
4806 fadescale = atof(value);
4811 if (lightscale <= 0)
4815 if (color[0] == color[1] && color[0] == color[2])
4817 color[0] *= overridecolor[0];
4818 color[1] *= overridecolor[1];
4819 color[2] *= overridecolor[2];
4821 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4822 color[0] = color[0] * light[0];
4823 color[1] = color[1] * light[1];
4824 color[2] = color[2] * light[2];
4827 case LIGHTTYPE_MINUSX:
4829 case LIGHTTYPE_RECIPX:
4831 VectorScale(color, (1.0f / 16.0f), color);
4833 case LIGHTTYPE_RECIPXX:
4835 VectorScale(color, (1.0f / 16.0f), color);
4838 case LIGHTTYPE_NONE:
4842 case LIGHTTYPE_MINUSXX:
4845 VectorAdd(origin, originhack, origin);
4847 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);
4850 Mem_Free(entfiledata);
4854 void R_Shadow_SetCursorLocationForView(void)
4857 vec3_t dest, endpos;
4859 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4860 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4861 if (trace.fraction < 1)
4863 dist = trace.fraction * r_editlights_cursordistance.value;
4864 push = r_editlights_cursorpushback.value;
4868 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4869 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4873 VectorClear( endpos );
4875 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4876 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4877 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4880 void R_Shadow_UpdateWorldLightSelection(void)
4882 if (r_editlights.integer)
4884 R_Shadow_SetCursorLocationForView();
4885 R_Shadow_SelectLightInView();
4888 R_Shadow_SelectLight(NULL);
4891 void R_Shadow_EditLights_Clear_f(void)
4893 R_Shadow_ClearWorldLights();
4896 void R_Shadow_EditLights_Reload_f(void)
4900 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4901 R_Shadow_ClearWorldLights();
4902 R_Shadow_LoadWorldLights();
4903 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4905 R_Shadow_LoadLightsFile();
4906 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4907 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4911 void R_Shadow_EditLights_Save_f(void)
4915 R_Shadow_SaveWorldLights();
4918 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4920 R_Shadow_ClearWorldLights();
4921 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4924 void R_Shadow_EditLights_ImportLightsFile_f(void)
4926 R_Shadow_ClearWorldLights();
4927 R_Shadow_LoadLightsFile();
4930 void R_Shadow_EditLights_Spawn_f(void)
4933 if (!r_editlights.integer)
4935 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4938 if (Cmd_Argc() != 1)
4940 Con_Print("r_editlights_spawn does not take parameters\n");
4943 color[0] = color[1] = color[2] = 1;
4944 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4947 void R_Shadow_EditLights_Edit_f(void)
4949 vec3_t origin, angles, color;
4950 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4951 int style, shadows, flags, normalmode, realtimemode;
4952 char cubemapname[MAX_INPUTLINE];
4953 if (!r_editlights.integer)
4955 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4958 if (!r_shadow_selectedlight)
4960 Con_Print("No selected light.\n");
4963 VectorCopy(r_shadow_selectedlight->origin, origin);
4964 VectorCopy(r_shadow_selectedlight->angles, angles);
4965 VectorCopy(r_shadow_selectedlight->color, color);
4966 radius = r_shadow_selectedlight->radius;
4967 style = r_shadow_selectedlight->style;
4968 if (r_shadow_selectedlight->cubemapname)
4969 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4972 shadows = r_shadow_selectedlight->shadow;
4973 corona = r_shadow_selectedlight->corona;
4974 coronasizescale = r_shadow_selectedlight->coronasizescale;
4975 ambientscale = r_shadow_selectedlight->ambientscale;
4976 diffusescale = r_shadow_selectedlight->diffusescale;
4977 specularscale = r_shadow_selectedlight->specularscale;
4978 flags = r_shadow_selectedlight->flags;
4979 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4980 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4981 if (!strcmp(Cmd_Argv(1), "origin"))
4983 if (Cmd_Argc() != 5)
4985 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
4988 origin[0] = atof(Cmd_Argv(2));
4989 origin[1] = atof(Cmd_Argv(3));
4990 origin[2] = atof(Cmd_Argv(4));
4992 else if (!strcmp(Cmd_Argv(1), "originx"))
4994 if (Cmd_Argc() != 3)
4996 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
4999 origin[0] = atof(Cmd_Argv(2));
5001 else if (!strcmp(Cmd_Argv(1), "originy"))
5003 if (Cmd_Argc() != 3)
5005 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5008 origin[1] = atof(Cmd_Argv(2));
5010 else if (!strcmp(Cmd_Argv(1), "originz"))
5012 if (Cmd_Argc() != 3)
5014 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5017 origin[2] = atof(Cmd_Argv(2));
5019 else if (!strcmp(Cmd_Argv(1), "move"))
5021 if (Cmd_Argc() != 5)
5023 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5026 origin[0] += atof(Cmd_Argv(2));
5027 origin[1] += atof(Cmd_Argv(3));
5028 origin[2] += atof(Cmd_Argv(4));
5030 else if (!strcmp(Cmd_Argv(1), "movex"))
5032 if (Cmd_Argc() != 3)
5034 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5037 origin[0] += atof(Cmd_Argv(2));
5039 else if (!strcmp(Cmd_Argv(1), "movey"))
5041 if (Cmd_Argc() != 3)
5043 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5046 origin[1] += atof(Cmd_Argv(2));
5048 else if (!strcmp(Cmd_Argv(1), "movez"))
5050 if (Cmd_Argc() != 3)
5052 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5055 origin[2] += atof(Cmd_Argv(2));
5057 else if (!strcmp(Cmd_Argv(1), "angles"))
5059 if (Cmd_Argc() != 5)
5061 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5064 angles[0] = atof(Cmd_Argv(2));
5065 angles[1] = atof(Cmd_Argv(3));
5066 angles[2] = atof(Cmd_Argv(4));
5068 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5070 if (Cmd_Argc() != 3)
5072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5075 angles[0] = atof(Cmd_Argv(2));
5077 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5079 if (Cmd_Argc() != 3)
5081 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5084 angles[1] = atof(Cmd_Argv(2));
5086 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5088 if (Cmd_Argc() != 3)
5090 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5093 angles[2] = atof(Cmd_Argv(2));
5095 else if (!strcmp(Cmd_Argv(1), "color"))
5097 if (Cmd_Argc() != 5)
5099 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5102 color[0] = atof(Cmd_Argv(2));
5103 color[1] = atof(Cmd_Argv(3));
5104 color[2] = atof(Cmd_Argv(4));
5106 else if (!strcmp(Cmd_Argv(1), "radius"))
5108 if (Cmd_Argc() != 3)
5110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5113 radius = atof(Cmd_Argv(2));
5115 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5117 if (Cmd_Argc() == 3)
5119 double scale = atof(Cmd_Argv(2));
5126 if (Cmd_Argc() != 5)
5128 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5131 color[0] *= atof(Cmd_Argv(2));
5132 color[1] *= atof(Cmd_Argv(3));
5133 color[2] *= atof(Cmd_Argv(4));
5136 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5138 if (Cmd_Argc() != 3)
5140 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5143 radius *= atof(Cmd_Argv(2));
5145 else if (!strcmp(Cmd_Argv(1), "style"))
5147 if (Cmd_Argc() != 3)
5149 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5152 style = atoi(Cmd_Argv(2));
5154 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5161 if (Cmd_Argc() == 3)
5162 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5166 else if (!strcmp(Cmd_Argv(1), "shadows"))
5168 if (Cmd_Argc() != 3)
5170 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5173 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5175 else if (!strcmp(Cmd_Argv(1), "corona"))
5177 if (Cmd_Argc() != 3)
5179 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5182 corona = atof(Cmd_Argv(2));
5184 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5186 if (Cmd_Argc() != 3)
5188 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5191 coronasizescale = atof(Cmd_Argv(2));
5193 else if (!strcmp(Cmd_Argv(1), "ambient"))
5195 if (Cmd_Argc() != 3)
5197 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5200 ambientscale = atof(Cmd_Argv(2));
5202 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5204 if (Cmd_Argc() != 3)
5206 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5209 diffusescale = atof(Cmd_Argv(2));
5211 else if (!strcmp(Cmd_Argv(1), "specular"))
5213 if (Cmd_Argc() != 3)
5215 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5218 specularscale = atof(Cmd_Argv(2));
5220 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5222 if (Cmd_Argc() != 3)
5224 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5227 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5229 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5231 if (Cmd_Argc() != 3)
5233 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5236 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5240 Con_Print("usage: r_editlights_edit [property] [value]\n");
5241 Con_Print("Selected light's properties:\n");
5242 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5243 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5244 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5245 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5246 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5247 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5248 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5249 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5250 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5251 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5252 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5253 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5254 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5255 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5258 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5259 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5262 void R_Shadow_EditLights_EditAll_f(void)
5268 if (!r_editlights.integer)
5270 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5274 // EditLights doesn't seem to have a "remove" command or something so:
5275 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5276 for (lightindex = 0;lightindex < range;lightindex++)
5278 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5281 R_Shadow_SelectLight(light);
5282 R_Shadow_EditLights_Edit_f();
5286 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5288 int lightnumber, lightcount;
5289 size_t lightindex, range;
5293 if (!r_editlights.integer)
5295 x = vid_conwidth.value - 240;
5297 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5300 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5301 for (lightindex = 0;lightindex < range;lightindex++)
5303 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5306 if (light == r_shadow_selectedlight)
5307 lightnumber = lightindex;
5310 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;
5311 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;
5313 if (r_shadow_selectedlight == NULL)
5315 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;
5316 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;
5317 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;
5318 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;
5319 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;
5320 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;
5321 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;
5322 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;
5323 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;
5324 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;
5325 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;
5326 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;
5327 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;
5328 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;
5329 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;
5332 void R_Shadow_EditLights_ToggleShadow_f(void)
5334 if (!r_editlights.integer)
5336 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5339 if (!r_shadow_selectedlight)
5341 Con_Print("No selected light.\n");
5344 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);
5347 void R_Shadow_EditLights_ToggleCorona_f(void)
5349 if (!r_editlights.integer)
5351 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5354 if (!r_shadow_selectedlight)
5356 Con_Print("No selected light.\n");
5359 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);
5362 void R_Shadow_EditLights_Remove_f(void)
5364 if (!r_editlights.integer)
5366 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5369 if (!r_shadow_selectedlight)
5371 Con_Print("No selected light.\n");
5374 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5375 r_shadow_selectedlight = NULL;
5378 void R_Shadow_EditLights_Help_f(void)
5381 "Documentation on r_editlights system:\n"
5383 "r_editlights : enable/disable editing mode\n"
5384 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5385 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5386 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5387 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5388 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5390 "r_editlights_help : this help\n"
5391 "r_editlights_clear : remove all lights\n"
5392 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5393 "r_editlights_save : save to .rtlights file\n"
5394 "r_editlights_spawn : create a light with default settings\n"
5395 "r_editlights_edit command : edit selected light - more documentation below\n"
5396 "r_editlights_remove : remove selected light\n"
5397 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5398 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5399 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5401 "origin x y z : set light location\n"
5402 "originx x: set x component of light location\n"
5403 "originy y: set y component of light location\n"
5404 "originz z: set z component of light location\n"
5405 "move x y z : adjust light location\n"
5406 "movex x: adjust x component of light location\n"
5407 "movey y: adjust y component of light location\n"
5408 "movez z: adjust z component of light location\n"
5409 "angles x y z : set light angles\n"
5410 "anglesx x: set x component of light angles\n"
5411 "anglesy y: set y component of light angles\n"
5412 "anglesz z: set z component of light angles\n"
5413 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5414 "radius radius : set radius (size) of light\n"
5415 "colorscale grey : multiply color of light (1 does nothing)\n"
5416 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5417 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5418 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5419 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5420 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5421 "shadows 1/0 : turn on/off shadows\n"
5422 "corona n : set corona intensity\n"
5423 "coronasize n : set corona size (0-1)\n"
5424 "ambient n : set ambient intensity (0-1)\n"
5425 "diffuse n : set diffuse intensity (0-1)\n"
5426 "specular n : set specular intensity (0-1)\n"
5427 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5428 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5429 "<nothing> : print light properties to console\n"
5433 void R_Shadow_EditLights_CopyInfo_f(void)
5435 if (!r_editlights.integer)
5437 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5440 if (!r_shadow_selectedlight)
5442 Con_Print("No selected light.\n");
5445 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5446 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5447 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5448 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5449 if (r_shadow_selectedlight->cubemapname)
5450 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5452 r_shadow_bufferlight.cubemapname[0] = 0;
5453 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5454 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5455 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5456 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5457 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5458 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5459 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5462 void R_Shadow_EditLights_PasteInfo_f(void)
5464 if (!r_editlights.integer)
5466 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5469 if (!r_shadow_selectedlight)
5471 Con_Print("No selected light.\n");
5474 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);
5477 void R_Shadow_EditLights_Init(void)
5479 Cvar_RegisterVariable(&r_editlights);
5480 Cvar_RegisterVariable(&r_editlights_cursordistance);
5481 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5482 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5483 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5484 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5485 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5486 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5487 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)");
5488 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5489 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5490 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5491 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)");
5492 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5493 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5494 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5495 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5496 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5497 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5498 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)");
5504 =============================================================================
5508 =============================================================================
5511 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5513 VectorClear(diffusecolor);
5514 VectorClear(diffusenormal);
5516 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5518 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5519 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5522 VectorSet(ambientcolor, 1, 1, 1);
5529 for (i = 0;i < r_refdef.scene.numlights;i++)
5531 light = r_refdef.scene.lights[i];
5532 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5533 f = 1 - VectorLength2(v);
5534 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5535 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);