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_shadowmapmaxsize;
183 int r_shadow_lightscissor[4];
185 int maxshadowtriangles;
188 int maxshadowvertices;
189 float *shadowvertex3f;
202 int r_shadow_buffer_numleafpvsbytes;
203 unsigned char *r_shadow_buffer_visitingleafpvs;
204 unsigned char *r_shadow_buffer_leafpvs;
205 int *r_shadow_buffer_leaflist;
207 int r_shadow_buffer_numsurfacepvsbytes;
208 unsigned char *r_shadow_buffer_surfacepvs;
209 int *r_shadow_buffer_surfacelist;
211 int r_shadow_buffer_numshadowtrispvsbytes;
212 unsigned char *r_shadow_buffer_shadowtrispvs;
213 int r_shadow_buffer_numlighttrispvsbytes;
214 unsigned char *r_shadow_buffer_lighttrispvs;
216 rtexturepool_t *r_shadow_texturepool;
217 rtexture_t *r_shadow_attenuationgradienttexture;
218 rtexture_t *r_shadow_attenuation2dtexture;
219 rtexture_t *r_shadow_attenuation3dtexture;
220 rtexture_t *r_shadow_lightcorona;
221 rtexture_t *r_shadow_shadowmaprectangletexture;
222 rtexture_t *r_shadow_shadowmap2dtexture;
223 rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
224 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
225 int r_shadow_shadowmapsize; // changes for each light based on distance
226 int r_shadow_shadowmaplod; // changes for each light based on distance
228 // lights are reloaded when this changes
229 char r_shadow_mapname[MAX_QPATH];
231 // used only for light filters (cubemaps)
232 rtexturepool_t *r_shadow_filters_texturepool;
234 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"};
235 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"};
236 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
237 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
238 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)"};
239 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"};
240 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
241 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
242 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
243 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
244 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
245 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
246 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
247 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
248 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
249 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)"};
250 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
251 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
252 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
253 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
254 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)"};
255 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"};
256 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
257 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
258 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"};
259 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
260 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
261 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)"};
262 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"};
263 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)"};
264 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
265 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"};
266 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "8", "shadowmap size bias"};
267 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "1", "shadowmap size scaling parameter"};
268 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
269 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
270 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
271 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
272 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
273 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)"};
274 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)"};
275 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
276 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"};
277 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
278 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
279 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
280 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
281 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
282 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
283 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
284 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
285 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
286 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
288 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
289 #define ATTENTABLESIZE 256
290 // 1D gradient, 2D circle and 3D sphere attenuation textures
291 #define ATTEN1DSIZE 32
292 #define ATTEN2DSIZE 64
293 #define ATTEN3DSIZE 32
295 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
296 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
297 static float r_shadow_attentable[ATTENTABLESIZE+1];
299 rtlight_t *r_shadow_compilingrtlight;
300 static memexpandablearray_t r_shadow_worldlightsarray;
301 dlight_t *r_shadow_selectedlight;
302 dlight_t r_shadow_bufferlight;
303 vec3_t r_editlights_cursorlocation;
305 extern int con_vislines;
307 typedef struct cubemapinfo_s
314 #define MAX_CUBEMAPS 256
315 static int numcubemaps;
316 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
318 void R_Shadow_UncompileWorldLights(void);
319 void R_Shadow_ClearWorldLights(void);
320 void R_Shadow_SaveWorldLights(void);
321 void R_Shadow_LoadWorldLights(void);
322 void R_Shadow_LoadLightsFile(void);
323 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
324 void R_Shadow_EditLights_Reload_f(void);
325 void R_Shadow_ValidateCvars(void);
326 static void R_Shadow_MakeTextures(void);
328 // VorteX: custom editor light sprites
329 #define EDLIGHTSPRSIZE 8
330 cachepic_t *r_editlights_sprcursor;
331 cachepic_t *r_editlights_sprlight;
332 cachepic_t *r_editlights_sprnoshadowlight;
333 cachepic_t *r_editlights_sprcubemaplight;
334 cachepic_t *r_editlights_sprcubemapnoshadowlight;
335 cachepic_t *r_editlights_sprselection;
337 void r_shadow_start(void)
339 // allocate vertex processing arrays
341 r_shadow_attenuationgradienttexture = NULL;
342 r_shadow_attenuation2dtexture = NULL;
343 r_shadow_attenuation3dtexture = NULL;
344 r_shadow_shadowmaprectangletexture = NULL;
345 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
346 r_shadow_shadowmapcubeprojectiontexture = NULL;
347 r_shadow_shadowmap2dtexture = NULL;
348 r_shadow_shadowmapmaxsize = 0;
349 r_shadow_shadowmapsize = 0;
350 r_shadow_shadowmaplod = 0;
351 r_shadow_fborectangle = 0;
352 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
354 r_shadow_texturepool = NULL;
355 r_shadow_filters_texturepool = NULL;
356 R_Shadow_ValidateCvars();
357 R_Shadow_MakeTextures();
358 maxshadowtriangles = 0;
359 shadowelements = NULL;
360 maxshadowvertices = 0;
361 shadowvertex3f = NULL;
369 shadowmarklist = NULL;
371 r_shadow_buffer_numleafpvsbytes = 0;
372 r_shadow_buffer_visitingleafpvs = NULL;
373 r_shadow_buffer_leafpvs = NULL;
374 r_shadow_buffer_leaflist = NULL;
375 r_shadow_buffer_numsurfacepvsbytes = 0;
376 r_shadow_buffer_surfacepvs = NULL;
377 r_shadow_buffer_surfacelist = NULL;
378 r_shadow_buffer_numshadowtrispvsbytes = 0;
379 r_shadow_buffer_shadowtrispvs = NULL;
380 r_shadow_buffer_numlighttrispvsbytes = 0;
381 r_shadow_buffer_lighttrispvs = NULL;
384 void r_shadow_shutdown(void)
388 R_Shadow_UncompileWorldLights();
391 r_shadow_attenuationgradienttexture = NULL;
392 r_shadow_attenuation2dtexture = NULL;
393 r_shadow_attenuation3dtexture = NULL;
394 r_shadow_shadowmaprectangletexture = NULL;
395 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
396 r_shadow_shadowmapcubeprojectiontexture = NULL;
397 r_shadow_shadowmap2dtexture = NULL;
398 r_shadow_shadowmapmaxsize = 0;
399 r_shadow_shadowmapsize = 0;
400 r_shadow_shadowmaplod = 0;
402 if (r_shadow_fborectangle)
403 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
404 r_shadow_fborectangle = 0;
406 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
407 if (r_shadow_fbocubeside[i])
408 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
409 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
412 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
415 R_FreeTexturePool(&r_shadow_texturepool);
416 R_FreeTexturePool(&r_shadow_filters_texturepool);
417 maxshadowtriangles = 0;
419 Mem_Free(shadowelements);
420 shadowelements = NULL;
422 Mem_Free(shadowvertex3f);
423 shadowvertex3f = NULL;
426 Mem_Free(vertexupdate);
429 Mem_Free(vertexremap);
435 Mem_Free(shadowmark);
438 Mem_Free(shadowmarklist);
439 shadowmarklist = NULL;
441 r_shadow_buffer_numleafpvsbytes = 0;
442 if (r_shadow_buffer_visitingleafpvs)
443 Mem_Free(r_shadow_buffer_visitingleafpvs);
444 r_shadow_buffer_visitingleafpvs = NULL;
445 if (r_shadow_buffer_leafpvs)
446 Mem_Free(r_shadow_buffer_leafpvs);
447 r_shadow_buffer_leafpvs = NULL;
448 if (r_shadow_buffer_leaflist)
449 Mem_Free(r_shadow_buffer_leaflist);
450 r_shadow_buffer_leaflist = NULL;
451 r_shadow_buffer_numsurfacepvsbytes = 0;
452 if (r_shadow_buffer_surfacepvs)
453 Mem_Free(r_shadow_buffer_surfacepvs);
454 r_shadow_buffer_surfacepvs = NULL;
455 if (r_shadow_buffer_surfacelist)
456 Mem_Free(r_shadow_buffer_surfacelist);
457 r_shadow_buffer_surfacelist = NULL;
458 r_shadow_buffer_numshadowtrispvsbytes = 0;
459 if (r_shadow_buffer_shadowtrispvs)
460 Mem_Free(r_shadow_buffer_shadowtrispvs);
461 r_shadow_buffer_numlighttrispvsbytes = 0;
462 if (r_shadow_buffer_lighttrispvs)
463 Mem_Free(r_shadow_buffer_lighttrispvs);
466 void r_shadow_newmap(void)
468 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
469 R_Shadow_EditLights_Reload_f();
472 void R_Shadow_Help_f(void)
475 "Documentation on r_shadow system:\n"
477 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
478 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
479 "r_shadow_debuglight : render only this light number (-1 = all)\n"
480 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
481 "r_shadow_gloss2intensity : brightness of forced gloss\n"
482 "r_shadow_glossintensity : brightness of textured gloss\n"
483 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
484 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
485 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
486 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
487 "r_shadow_portallight : use portal visibility for static light precomputation\n"
488 "r_shadow_projectdistance : shadow volume projection distance\n"
489 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
490 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
491 "r_shadow_realtime_world : use high quality world lighting mode\n"
492 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
493 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
494 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
495 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
496 "r_shadow_scissor : use scissor optimization\n"
497 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
498 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
499 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
500 "r_showlighting : useful for performance testing; bright = slow!\n"
501 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
503 "r_shadow_help : this help\n"
507 void R_Shadow_Init(void)
509 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
510 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
511 Cvar_RegisterVariable(&r_shadow_usenormalmap);
512 Cvar_RegisterVariable(&r_shadow_debuglight);
513 Cvar_RegisterVariable(&r_shadow_gloss);
514 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
515 Cvar_RegisterVariable(&r_shadow_glossintensity);
516 Cvar_RegisterVariable(&r_shadow_glossexponent);
517 Cvar_RegisterVariable(&r_shadow_glossexact);
518 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
519 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
520 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
521 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
522 Cvar_RegisterVariable(&r_shadow_portallight);
523 Cvar_RegisterVariable(&r_shadow_projectdistance);
524 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
525 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
526 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
527 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
528 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
529 Cvar_RegisterVariable(&r_shadow_realtime_world);
530 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
531 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
532 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
533 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
534 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
535 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
536 Cvar_RegisterVariable(&r_shadow_scissor);
537 Cvar_RegisterVariable(&r_shadow_shadowmapping);
538 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
539 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
540 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
541 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
542 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
543 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
544 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
545 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
546 Cvar_RegisterVariable(&r_shadow_culltriangles);
547 Cvar_RegisterVariable(&r_shadow_polygonfactor);
548 Cvar_RegisterVariable(&r_shadow_polygonoffset);
549 Cvar_RegisterVariable(&r_shadow_texture3d);
550 Cvar_RegisterVariable(&r_coronas);
551 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
552 Cvar_RegisterVariable(&r_coronas_occlusionquery);
553 Cvar_RegisterVariable(&gl_flashblend);
554 Cvar_RegisterVariable(&gl_ext_separatestencil);
555 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
556 if (gamemode == GAME_TENEBRAE)
558 Cvar_SetValue("r_shadow_gloss", 2);
559 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
561 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
562 R_Shadow_EditLights_Init();
563 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
564 maxshadowtriangles = 0;
565 shadowelements = NULL;
566 maxshadowvertices = 0;
567 shadowvertex3f = NULL;
575 shadowmarklist = NULL;
577 r_shadow_buffer_numleafpvsbytes = 0;
578 r_shadow_buffer_visitingleafpvs = NULL;
579 r_shadow_buffer_leafpvs = NULL;
580 r_shadow_buffer_leaflist = NULL;
581 r_shadow_buffer_numsurfacepvsbytes = 0;
582 r_shadow_buffer_surfacepvs = NULL;
583 r_shadow_buffer_surfacelist = NULL;
584 r_shadow_buffer_shadowtrispvs = NULL;
585 r_shadow_buffer_lighttrispvs = NULL;
586 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
589 matrix4x4_t matrix_attenuationxyz =
592 {0.5, 0.0, 0.0, 0.5},
593 {0.0, 0.5, 0.0, 0.5},
594 {0.0, 0.0, 0.5, 0.5},
599 matrix4x4_t matrix_attenuationz =
602 {0.0, 0.0, 0.5, 0.5},
603 {0.0, 0.0, 0.0, 0.5},
604 {0.0, 0.0, 0.0, 0.5},
609 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
611 // make sure shadowelements is big enough for this volume
612 if (maxshadowtriangles < numtriangles)
614 maxshadowtriangles = numtriangles;
616 Mem_Free(shadowelements);
617 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
619 // make sure shadowvertex3f is big enough for this volume
620 if (maxshadowvertices < numvertices)
622 maxshadowvertices = numvertices;
624 Mem_Free(shadowvertex3f);
625 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
629 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
631 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
632 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
633 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
634 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
635 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
637 if (r_shadow_buffer_visitingleafpvs)
638 Mem_Free(r_shadow_buffer_visitingleafpvs);
639 if (r_shadow_buffer_leafpvs)
640 Mem_Free(r_shadow_buffer_leafpvs);
641 if (r_shadow_buffer_leaflist)
642 Mem_Free(r_shadow_buffer_leaflist);
643 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
644 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
645 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
646 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
648 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
650 if (r_shadow_buffer_surfacepvs)
651 Mem_Free(r_shadow_buffer_surfacepvs);
652 if (r_shadow_buffer_surfacelist)
653 Mem_Free(r_shadow_buffer_surfacelist);
654 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
655 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
656 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
658 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
660 if (r_shadow_buffer_shadowtrispvs)
661 Mem_Free(r_shadow_buffer_shadowtrispvs);
662 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
663 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
665 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
667 if (r_shadow_buffer_lighttrispvs)
668 Mem_Free(r_shadow_buffer_lighttrispvs);
669 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
670 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
674 void R_Shadow_PrepareShadowMark(int numtris)
676 // make sure shadowmark is big enough for this volume
677 if (maxshadowmark < numtris)
679 maxshadowmark = numtris;
681 Mem_Free(shadowmark);
683 Mem_Free(shadowmarklist);
684 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
685 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
689 // if shadowmarkcount wrapped we clear the array and adjust accordingly
690 if (shadowmarkcount == 0)
693 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
698 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)
701 int outtriangles = 0, outvertices = 0;
704 float ratio, direction[3], projectvector[3];
706 if (projectdirection)
707 VectorScale(projectdirection, projectdistance, projectvector);
709 VectorClear(projectvector);
711 // create the vertices
712 if (projectdirection)
714 for (i = 0;i < numshadowmarktris;i++)
716 element = inelement3i + shadowmarktris[i] * 3;
717 for (j = 0;j < 3;j++)
719 if (vertexupdate[element[j]] != vertexupdatenum)
721 vertexupdate[element[j]] = vertexupdatenum;
722 vertexremap[element[j]] = outvertices;
723 vertex = invertex3f + element[j] * 3;
724 // project one copy of the vertex according to projectvector
725 VectorCopy(vertex, outvertex3f);
726 VectorAdd(vertex, projectvector, (outvertex3f + 3));
735 for (i = 0;i < numshadowmarktris;i++)
737 element = inelement3i + shadowmarktris[i] * 3;
738 for (j = 0;j < 3;j++)
740 if (vertexupdate[element[j]] != vertexupdatenum)
742 vertexupdate[element[j]] = vertexupdatenum;
743 vertexremap[element[j]] = outvertices;
744 vertex = invertex3f + element[j] * 3;
745 // project one copy of the vertex to the sphere radius of the light
746 // (FIXME: would projecting it to the light box be better?)
747 VectorSubtract(vertex, projectorigin, direction);
748 ratio = projectdistance / VectorLength(direction);
749 VectorCopy(vertex, outvertex3f);
750 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
758 if (r_shadow_frontsidecasting.integer)
760 for (i = 0;i < numshadowmarktris;i++)
762 int remappedelement[3];
764 const int *neighbortriangle;
766 markindex = shadowmarktris[i] * 3;
767 element = inelement3i + markindex;
768 neighbortriangle = inneighbor3i + markindex;
769 // output the front and back triangles
770 outelement3i[0] = vertexremap[element[0]];
771 outelement3i[1] = vertexremap[element[1]];
772 outelement3i[2] = vertexremap[element[2]];
773 outelement3i[3] = vertexremap[element[2]] + 1;
774 outelement3i[4] = vertexremap[element[1]] + 1;
775 outelement3i[5] = vertexremap[element[0]] + 1;
779 // output the sides (facing outward from this triangle)
780 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
782 remappedelement[0] = vertexremap[element[0]];
783 remappedelement[1] = vertexremap[element[1]];
784 outelement3i[0] = remappedelement[1];
785 outelement3i[1] = remappedelement[0];
786 outelement3i[2] = remappedelement[0] + 1;
787 outelement3i[3] = remappedelement[1];
788 outelement3i[4] = remappedelement[0] + 1;
789 outelement3i[5] = remappedelement[1] + 1;
794 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
796 remappedelement[1] = vertexremap[element[1]];
797 remappedelement[2] = vertexremap[element[2]];
798 outelement3i[0] = remappedelement[2];
799 outelement3i[1] = remappedelement[1];
800 outelement3i[2] = remappedelement[1] + 1;
801 outelement3i[3] = remappedelement[2];
802 outelement3i[4] = remappedelement[1] + 1;
803 outelement3i[5] = remappedelement[2] + 1;
808 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
810 remappedelement[0] = vertexremap[element[0]];
811 remappedelement[2] = vertexremap[element[2]];
812 outelement3i[0] = remappedelement[0];
813 outelement3i[1] = remappedelement[2];
814 outelement3i[2] = remappedelement[2] + 1;
815 outelement3i[3] = remappedelement[0];
816 outelement3i[4] = remappedelement[2] + 1;
817 outelement3i[5] = remappedelement[0] + 1;
826 for (i = 0;i < numshadowmarktris;i++)
828 int remappedelement[3];
830 const int *neighbortriangle;
832 markindex = shadowmarktris[i] * 3;
833 element = inelement3i + markindex;
834 neighbortriangle = inneighbor3i + markindex;
835 // output the front and back triangles
836 outelement3i[0] = vertexremap[element[2]];
837 outelement3i[1] = vertexremap[element[1]];
838 outelement3i[2] = vertexremap[element[0]];
839 outelement3i[3] = vertexremap[element[0]] + 1;
840 outelement3i[4] = vertexremap[element[1]] + 1;
841 outelement3i[5] = vertexremap[element[2]] + 1;
845 // output the sides (facing outward from this triangle)
846 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
848 remappedelement[0] = vertexremap[element[0]];
849 remappedelement[1] = vertexremap[element[1]];
850 outelement3i[0] = remappedelement[0];
851 outelement3i[1] = remappedelement[1];
852 outelement3i[2] = remappedelement[1] + 1;
853 outelement3i[3] = remappedelement[0];
854 outelement3i[4] = remappedelement[1] + 1;
855 outelement3i[5] = remappedelement[0] + 1;
860 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
862 remappedelement[1] = vertexremap[element[1]];
863 remappedelement[2] = vertexremap[element[2]];
864 outelement3i[0] = remappedelement[1];
865 outelement3i[1] = remappedelement[2];
866 outelement3i[2] = remappedelement[2] + 1;
867 outelement3i[3] = remappedelement[1];
868 outelement3i[4] = remappedelement[2] + 1;
869 outelement3i[5] = remappedelement[1] + 1;
874 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
876 remappedelement[0] = vertexremap[element[0]];
877 remappedelement[2] = vertexremap[element[2]];
878 outelement3i[0] = remappedelement[2];
879 outelement3i[1] = remappedelement[0];
880 outelement3i[2] = remappedelement[0] + 1;
881 outelement3i[3] = remappedelement[2];
882 outelement3i[4] = remappedelement[0] + 1;
883 outelement3i[5] = remappedelement[2] + 1;
891 *outnumvertices = outvertices;
895 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)
898 int outtriangles = 0, outvertices = 0;
901 float ratio, direction[3], projectvector[3];
904 if (projectdirection)
905 VectorScale(projectdirection, projectdistance, projectvector);
907 VectorClear(projectvector);
909 for (i = 0;i < numshadowmarktris;i++)
911 int remappedelement[3];
913 const int *neighbortriangle;
915 markindex = shadowmarktris[i] * 3;
916 neighbortriangle = inneighbor3i + markindex;
917 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
918 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
919 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
920 if (side[0] + side[1] + side[2] == 0)
924 element = inelement3i + markindex;
926 // create the vertices
927 for (j = 0;j < 3;j++)
929 if (side[j] + side[j+1] == 0)
932 if (vertexupdate[k] != vertexupdatenum)
934 vertexupdate[k] = vertexupdatenum;
935 vertexremap[k] = outvertices;
936 vertex = invertex3f + k * 3;
937 VectorCopy(vertex, outvertex3f);
938 if (projectdirection)
940 // project one copy of the vertex according to projectvector
941 VectorAdd(vertex, projectvector, (outvertex3f + 3));
945 // project one copy of the vertex to the sphere radius of the light
946 // (FIXME: would projecting it to the light box be better?)
947 VectorSubtract(vertex, projectorigin, direction);
948 ratio = projectdistance / VectorLength(direction);
949 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
956 // output the sides (facing outward from this triangle)
959 remappedelement[0] = vertexremap[element[0]];
960 remappedelement[1] = vertexremap[element[1]];
961 outelement3i[0] = remappedelement[1];
962 outelement3i[1] = remappedelement[0];
963 outelement3i[2] = remappedelement[0] + 1;
964 outelement3i[3] = remappedelement[1];
965 outelement3i[4] = remappedelement[0] + 1;
966 outelement3i[5] = remappedelement[1] + 1;
973 remappedelement[1] = vertexremap[element[1]];
974 remappedelement[2] = vertexremap[element[2]];
975 outelement3i[0] = remappedelement[2];
976 outelement3i[1] = remappedelement[1];
977 outelement3i[2] = remappedelement[1] + 1;
978 outelement3i[3] = remappedelement[2];
979 outelement3i[4] = remappedelement[1] + 1;
980 outelement3i[5] = remappedelement[2] + 1;
987 remappedelement[0] = vertexremap[element[0]];
988 remappedelement[2] = vertexremap[element[2]];
989 outelement3i[0] = remappedelement[0];
990 outelement3i[1] = remappedelement[2];
991 outelement3i[2] = remappedelement[2] + 1;
992 outelement3i[3] = remappedelement[0];
993 outelement3i[4] = remappedelement[2] + 1;
994 outelement3i[5] = remappedelement[0] + 1;
1001 *outnumvertices = outvertices;
1002 return outtriangles;
1005 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)
1011 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1013 tend = firsttriangle + numtris;
1014 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1016 // surface box entirely inside light box, no box cull
1017 if (projectdirection)
1019 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1021 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1022 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1023 shadowmarklist[numshadowmark++] = t;
1028 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1029 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1030 shadowmarklist[numshadowmark++] = t;
1035 // surface box not entirely inside light box, cull each triangle
1036 if (projectdirection)
1038 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1040 v[0] = invertex3f + e[0] * 3;
1041 v[1] = invertex3f + e[1] * 3;
1042 v[2] = invertex3f + e[2] * 3;
1043 TriangleNormal(v[0], v[1], v[2], normal);
1044 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1045 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1046 shadowmarklist[numshadowmark++] = t;
1051 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1053 v[0] = invertex3f + e[0] * 3;
1054 v[1] = invertex3f + e[1] * 3;
1055 v[2] = invertex3f + e[2] * 3;
1056 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1057 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1058 shadowmarklist[numshadowmark++] = t;
1064 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1069 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1071 // check if the shadow volume intersects the near plane
1073 // a ray between the eye and light origin may intersect the caster,
1074 // indicating that the shadow may touch the eye location, however we must
1075 // test the near plane (a polygon), not merely the eye location, so it is
1076 // easiest to enlarge the caster bounding shape slightly for this.
1082 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)
1084 int i, tris, outverts;
1085 if (projectdistance < 0.1)
1087 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1090 if (!numverts || !nummarktris)
1092 // make sure shadowelements is big enough for this volume
1093 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1094 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1096 if (maxvertexupdate < numverts)
1098 maxvertexupdate = numverts;
1100 Mem_Free(vertexupdate);
1102 Mem_Free(vertexremap);
1103 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1104 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1105 vertexupdatenum = 0;
1108 if (vertexupdatenum == 0)
1110 vertexupdatenum = 1;
1111 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1112 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1115 for (i = 0;i < nummarktris;i++)
1116 shadowmark[marktris[i]] = shadowmarkcount;
1118 if (r_shadow_compilingrtlight)
1120 // if we're compiling an rtlight, capture the mesh
1121 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1122 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1123 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1124 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1128 // decide which type of shadow to generate and set stencil mode
1129 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1130 // generate the sides or a solid volume, depending on type
1131 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1132 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1134 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1135 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1136 r_refdef.stats.lights_shadowtriangles += tris;
1138 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1139 GL_LockArrays(0, outverts);
1140 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1142 // increment stencil if frontface is infront of depthbuffer
1143 GL_CullFace(r_refdef.view.cullface_front);
1144 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1145 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1146 // decrement stencil if backface is infront of depthbuffer
1147 GL_CullFace(r_refdef.view.cullface_back);
1148 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1150 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1152 // decrement stencil if backface is behind depthbuffer
1153 GL_CullFace(r_refdef.view.cullface_front);
1154 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1155 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1156 // increment stencil if frontface is behind depthbuffer
1157 GL_CullFace(r_refdef.view.cullface_back);
1158 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1160 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1161 GL_LockArrays(0, 0);
1166 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)
1168 int i, tris = nummarktris;
1171 if (!numverts || !nummarktris)
1173 // make sure shadowelements is big enough for this mesh
1174 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1175 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1177 // gather up the (sparse) triangles into one array
1178 outelement3i = shadowelements;
1179 for (i = 0;i < nummarktris;i++)
1181 element = elements + marktris[i] * 3;
1182 outelement3i[0] = element[0];
1183 outelement3i[1] = element[1];
1184 outelement3i[2] = element[2];
1188 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1189 r_refdef.stats.lights_shadowtriangles += tris;
1190 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1191 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1194 static void R_Shadow_MakeTextures_MakeCorona(void)
1198 unsigned char pixels[32][32][4];
1199 for (y = 0;y < 32;y++)
1201 dy = (y - 15.5f) * (1.0f / 16.0f);
1202 for (x = 0;x < 32;x++)
1204 dx = (x - 15.5f) * (1.0f / 16.0f);
1205 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1206 a = bound(0, a, 255);
1207 pixels[y][x][0] = a;
1208 pixels[y][x][1] = a;
1209 pixels[y][x][2] = a;
1210 pixels[y][x][3] = 255;
1213 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1216 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1218 float dist = sqrt(x*x+y*y+z*z);
1219 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1220 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1221 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1224 static void R_Shadow_MakeTextures(void)
1227 float intensity, dist;
1229 R_FreeTexturePool(&r_shadow_texturepool);
1230 r_shadow_texturepool = R_AllocTexturePool();
1231 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1232 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1233 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1234 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1235 for (x = 0;x <= ATTENTABLESIZE;x++)
1237 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1238 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1239 r_shadow_attentable[x] = bound(0, intensity, 1);
1241 // 1D gradient texture
1242 for (x = 0;x < ATTEN1DSIZE;x++)
1243 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1244 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);
1245 // 2D circle texture
1246 for (y = 0;y < ATTEN2DSIZE;y++)
1247 for (x = 0;x < ATTEN2DSIZE;x++)
1248 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);
1249 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);
1250 // 3D sphere texture
1251 if (r_shadow_texture3d.integer && gl_texture3d)
1253 for (z = 0;z < ATTEN3DSIZE;z++)
1254 for (y = 0;y < ATTEN3DSIZE;y++)
1255 for (x = 0;x < ATTEN3DSIZE;x++)
1256 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));
1257 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);
1260 r_shadow_attenuation3dtexture = NULL;
1263 R_Shadow_MakeTextures_MakeCorona();
1265 // Editor light sprites
1266 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1267 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1268 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1269 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1270 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1271 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1274 void R_Shadow_ValidateCvars(void)
1276 if (r_shadow_texture3d.integer && !gl_texture3d)
1277 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1278 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1279 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1280 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1281 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1284 void R_Shadow_RenderMode_Begin(void)
1288 R_Shadow_ValidateCvars();
1290 if (!r_shadow_attenuation2dtexture
1291 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1292 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1293 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1294 R_Shadow_MakeTextures();
1297 R_Mesh_ColorPointer(NULL, 0, 0);
1298 R_Mesh_ResetTextureState();
1299 GL_BlendFunc(GL_ONE, GL_ZERO);
1300 GL_DepthRange(0, 1);
1301 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1303 GL_DepthMask(false);
1304 GL_Color(0, 0, 0, 1);
1305 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
1307 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1309 if (gl_ext_separatestencil.integer)
1311 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1312 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1314 else if (gl_ext_stenciltwoside.integer)
1316 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1317 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1321 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1322 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1325 if (r_glsl.integer && gl_support_fragment_shader)
1326 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1327 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1328 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1330 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1333 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1334 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1335 r_shadow_drawbuffer = drawbuffer;
1336 r_shadow_readbuffer = readbuffer;
1339 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1341 rsurface.rtlight = rtlight;
1344 void R_Shadow_RenderMode_Reset(void)
1347 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1349 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1351 if (gl_support_ext_framebuffer_object)
1353 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1355 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1356 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1357 R_SetViewport(&r_refdef.view.viewport);
1358 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1359 R_Mesh_ColorPointer(NULL, 0, 0);
1360 R_Mesh_ResetTextureState();
1361 GL_DepthRange(0, 1);
1363 GL_DepthMask(false);
1364 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1365 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1366 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1367 qglStencilMask(~0);CHECKGLERROR
1368 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1369 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1370 GL_CullFace(r_refdef.view.cullface_back);
1371 GL_Color(1, 1, 1, 1);
1372 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1373 GL_BlendFunc(GL_ONE, GL_ZERO);
1374 R_SetupGenericShader(false);
1375 r_shadow_usingshadowmaprect = false;
1376 r_shadow_usingshadowmapcube = false;
1377 r_shadow_usingshadowmap2d = false;
1381 void R_Shadow_ClearStencil(void)
1384 GL_Clear(GL_STENCIL_BUFFER_BIT);
1385 r_refdef.stats.lights_clears++;
1388 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1390 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1391 if (r_shadow_rendermode == mode)
1394 R_Shadow_RenderMode_Reset();
1395 GL_ColorMask(0, 0, 0, 0);
1396 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1397 R_SetupDepthOrShadowShader();
1398 qglDepthFunc(GL_LESS);CHECKGLERROR
1399 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1400 r_shadow_rendermode = mode;
1405 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1406 GL_CullFace(GL_NONE);
1407 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1408 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1410 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1411 GL_CullFace(GL_NONE);
1412 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1413 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1415 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1416 GL_CullFace(GL_NONE);
1417 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1418 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1419 qglStencilMask(~0);CHECKGLERROR
1420 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1421 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1422 qglStencilMask(~0);CHECKGLERROR
1423 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1425 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1426 GL_CullFace(GL_NONE);
1427 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1428 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1429 qglStencilMask(~0);CHECKGLERROR
1430 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1431 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1432 qglStencilMask(~0);CHECKGLERROR
1433 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1438 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1443 float nearclip, farclip;
1444 r_viewport_t viewport;
1446 maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
1447 if (r_shadow_shadowmapmaxsize != maxsize)
1449 r_shadow_shadowmapmaxsize = maxsize;
1451 if (r_shadow_fborectangle)
1452 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
1453 r_shadow_fborectangle = 0;
1456 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
1459 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
1460 if (r_shadow_fbocubeside[i])
1461 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
1462 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
1464 if (r_shadow_shadowmaprectangletexture)
1465 R_FreeTexture(r_shadow_shadowmaprectangletexture);
1466 r_shadow_shadowmaprectangletexture = NULL;
1468 if (r_shadow_shadowmap2dtexture)
1469 R_FreeTexture(r_shadow_shadowmap2dtexture);
1470 r_shadow_shadowmap2dtexture = NULL;
1472 if (r_shadow_shadowmapcubeprojectiontexture)
1473 R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
1474 r_shadow_shadowmapcubeprojectiontexture = NULL;
1476 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
1477 if (r_shadow_shadowmapcubetexture[i])
1478 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
1479 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
1483 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1485 r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1486 r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1487 r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
1488 r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
1489 r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
1490 if (!r_shadow_shadowmapcubeprojectiontexture)
1491 r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
1492 if (r_shadow_shadowmapping.integer == 1)
1494 // complex unrolled cube approach (more flexible)
1495 if (!r_shadow_shadowmap2dtexture)
1498 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4);
1499 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1500 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1501 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1505 R_Shadow_RenderMode_Reset();
1506 if (r_shadow_shadowmap2dtexture)
1508 // render depth into the fbo, do not render color at all
1509 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1510 qglDrawBuffer(GL_NONE);CHECKGLERROR
1511 qglReadBuffer(GL_NONE);CHECKGLERROR
1512 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1513 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1515 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1516 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1518 R_SetupDepthOrShadowShader();
1522 R_SetupShowDepthShader();
1523 qglClearColor(1,1,1,1);CHECKGLERROR
1525 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1526 r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
1527 r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
1528 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1530 else if (r_shadow_shadowmapping.integer == 2)
1532 // complex unrolled cube approach (more flexible)
1533 if (!r_shadow_shadowmaprectangletexture)
1536 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4);
1537 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1538 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1539 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1543 R_Shadow_RenderMode_Reset();
1544 if (r_shadow_shadowmaprectangletexture)
1546 // render depth into the fbo, do not render color at all
1547 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1548 qglDrawBuffer(GL_NONE);CHECKGLERROR
1549 qglReadBuffer(GL_NONE);CHECKGLERROR
1550 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1551 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1553 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1554 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1556 R_SetupDepthOrShadowShader();
1560 R_SetupShowDepthShader();
1561 qglClearColor(1,1,1,1);CHECKGLERROR
1563 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
1564 r_shadow_shadowmap_texturescale[0] = size;
1565 r_shadow_shadowmap_texturescale[1] = size;
1566 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1568 else if (r_shadow_shadowmapping.integer == 3)
1570 // simple cube approach
1571 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1574 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size);
1575 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1576 for (i = 0;i < 6;i++)
1578 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1579 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
1584 R_Shadow_RenderMode_Reset();
1585 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1587 // render depth into the fbo, do not render color at all
1588 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1589 qglDrawBuffer(GL_NONE);CHECKGLERROR
1590 qglReadBuffer(GL_NONE);CHECKGLERROR
1591 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1592 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1594 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1595 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1597 R_SetupDepthOrShadowShader();
1601 R_SetupShowDepthShader();
1602 qglClearColor(1,1,1,1);CHECKGLERROR
1604 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1605 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1606 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1607 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1610 R_SetViewport(&viewport);
1611 GL_PolygonOffset(0, 0);
1612 GL_CullFace(GL_NONE); // quake is backwards
1613 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1616 qglClearDepth(1);CHECKGLERROR
1619 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1623 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1626 R_Shadow_RenderMode_Reset();
1627 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1630 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1634 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1635 // only draw light where this geometry was already rendered AND the
1636 // stencil is 128 (values other than this mean shadow)
1637 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1639 r_shadow_rendermode = r_shadow_lightingrendermode;
1640 // do global setup needed for the chosen lighting mode
1641 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1643 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1644 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1648 if (r_shadow_shadowmapping.integer == 1)
1650 r_shadow_usingshadowmap2d = true;
1651 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1654 else if (r_shadow_shadowmapping.integer == 2)
1656 r_shadow_usingshadowmaprect = true;
1657 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1660 else if (r_shadow_shadowmapping.integer == 3)
1662 r_shadow_usingshadowmapcube = true;
1663 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1668 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1669 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1670 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1674 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1677 R_Shadow_RenderMode_Reset();
1678 GL_BlendFunc(GL_ONE, GL_ONE);
1679 GL_DepthRange(0, 1);
1680 GL_DepthTest(r_showshadowvolumes.integer < 2);
1681 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1682 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1683 GL_CullFace(GL_NONE);
1684 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1687 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1690 R_Shadow_RenderMode_Reset();
1691 GL_BlendFunc(GL_ONE, GL_ONE);
1692 GL_DepthRange(0, 1);
1693 GL_DepthTest(r_showlighting.integer < 2);
1694 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1697 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1701 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1702 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1704 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1707 void R_Shadow_RenderMode_End(void)
1710 R_Shadow_RenderMode_Reset();
1711 R_Shadow_RenderMode_ActiveLight(NULL);
1713 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
1714 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1717 int bboxedges[12][2] =
1736 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1738 int i, ix1, iy1, ix2, iy2;
1739 float x1, y1, x2, y2;
1741 float vertex[20][3];
1750 r_shadow_lightscissor[0] = r_refdef.view.x;
1751 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
1752 r_shadow_lightscissor[2] = r_refdef.view.width;
1753 r_shadow_lightscissor[3] = r_refdef.view.height;
1755 if (!r_shadow_scissor.integer)
1758 // if view is inside the light box, just say yes it's visible
1759 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1762 x1 = y1 = x2 = y2 = 0;
1764 // transform all corners that are infront of the nearclip plane
1765 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1766 plane4f[3] = r_refdef.view.frustum[4].dist;
1768 for (i = 0;i < 8;i++)
1770 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1771 dist[i] = DotProduct4(corner[i], plane4f);
1772 sign[i] = dist[i] > 0;
1775 VectorCopy(corner[i], vertex[numvertices]);
1779 // if some points are behind the nearclip, add clipped edge points to make
1780 // sure that the scissor boundary is complete
1781 if (numvertices > 0 && numvertices < 8)
1783 // add clipped edge points
1784 for (i = 0;i < 12;i++)
1786 j = bboxedges[i][0];
1787 k = bboxedges[i][1];
1788 if (sign[j] != sign[k])
1790 f = dist[j] / (dist[j] - dist[k]);
1791 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1797 // if we have no points to check, the light is behind the view plane
1801 // if we have some points to transform, check what screen area is covered
1802 x1 = y1 = x2 = y2 = 0;
1804 //Con_Printf("%i vertices to transform...\n", numvertices);
1805 for (i = 0;i < numvertices;i++)
1807 VectorCopy(vertex[i], v);
1808 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1809 //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]);
1812 if (x1 > v2[0]) x1 = v2[0];
1813 if (x2 < v2[0]) x2 = v2[0];
1814 if (y1 > v2[1]) y1 = v2[1];
1815 if (y2 < v2[1]) y2 = v2[1];
1824 // now convert the scissor rectangle to integer screen coordinates
1825 ix1 = (int)(x1 - 1.0f);
1826 iy1 = (int)(y1 - 1.0f);
1827 ix2 = (int)(x2 + 1.0f);
1828 iy2 = (int)(y2 + 1.0f);
1829 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1831 // clamp it to the screen
1832 if (ix1 < r_refdef.view.x) ix1 = r_refdef.view.x;
1833 if (iy1 < r_refdef.view.y) iy1 = r_refdef.view.y;
1834 if (ix2 > r_refdef.view.x + r_refdef.view.width) ix2 = r_refdef.view.x + r_refdef.view.width;
1835 if (iy2 > r_refdef.view.y + r_refdef.view.height) iy2 = r_refdef.view.y + r_refdef.view.height;
1837 // if it is inside out, it's not visible
1838 if (ix2 <= ix1 || iy2 <= iy1)
1841 // the light area is visible, set up the scissor rectangle
1842 r_shadow_lightscissor[0] = ix1;
1843 r_shadow_lightscissor[1] = vid.height - iy2;
1844 r_shadow_lightscissor[2] = ix2 - ix1;
1845 r_shadow_lightscissor[3] = iy2 - iy1;
1847 r_refdef.stats.lights_scissored++;
1851 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1853 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1854 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1855 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1856 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1857 if (r_textureunits.integer >= 3)
1859 if (VectorLength2(diffusecolor) > 0)
1861 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1863 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1864 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1865 if ((dot = DotProduct(n, v)) < 0)
1867 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1868 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1871 VectorCopy(ambientcolor, color4f);
1872 if (r_refdef.fogenabled)
1875 f = FogPoint_Model(vertex3f);
1876 VectorScale(color4f, f, color4f);
1883 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1885 VectorCopy(ambientcolor, color4f);
1886 if (r_refdef.fogenabled)
1889 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1890 f = FogPoint_Model(vertex3f);
1891 VectorScale(color4f, f, color4f);
1897 else if (r_textureunits.integer >= 2)
1899 if (VectorLength2(diffusecolor) > 0)
1901 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1903 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1904 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1906 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1907 if ((dot = DotProduct(n, v)) < 0)
1909 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1910 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1911 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1912 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1916 color4f[0] = ambientcolor[0] * distintensity;
1917 color4f[1] = ambientcolor[1] * distintensity;
1918 color4f[2] = ambientcolor[2] * distintensity;
1920 if (r_refdef.fogenabled)
1923 f = FogPoint_Model(vertex3f);
1924 VectorScale(color4f, f, color4f);
1928 VectorClear(color4f);
1934 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1936 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1937 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1939 color4f[0] = ambientcolor[0] * distintensity;
1940 color4f[1] = ambientcolor[1] * distintensity;
1941 color4f[2] = ambientcolor[2] * distintensity;
1942 if (r_refdef.fogenabled)
1945 f = FogPoint_Model(vertex3f);
1946 VectorScale(color4f, f, color4f);
1950 VectorClear(color4f);
1957 if (VectorLength2(diffusecolor) > 0)
1959 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1961 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1962 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1964 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1965 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1966 if ((dot = DotProduct(n, v)) < 0)
1968 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1969 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
1970 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
1971 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
1975 color4f[0] = ambientcolor[0] * distintensity;
1976 color4f[1] = ambientcolor[1] * distintensity;
1977 color4f[2] = ambientcolor[2] * distintensity;
1979 if (r_refdef.fogenabled)
1982 f = FogPoint_Model(vertex3f);
1983 VectorScale(color4f, f, color4f);
1987 VectorClear(color4f);
1993 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1995 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1996 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
1998 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
1999 color4f[0] = ambientcolor[0] * distintensity;
2000 color4f[1] = ambientcolor[1] * distintensity;
2001 color4f[2] = ambientcolor[2] * distintensity;
2002 if (r_refdef.fogenabled)
2005 f = FogPoint_Model(vertex3f);
2006 VectorScale(color4f, f, color4f);
2010 VectorClear(color4f);
2017 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2019 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2022 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2023 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2024 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2025 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2026 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2028 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2030 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2031 // the cubemap normalizes this for us
2032 out3f[0] = DotProduct(svector3f, lightdir);
2033 out3f[1] = DotProduct(tvector3f, lightdir);
2034 out3f[2] = DotProduct(normal3f, lightdir);
2038 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2041 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2042 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2043 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2044 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2045 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2046 float lightdir[3], eyedir[3], halfdir[3];
2047 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2049 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2050 VectorNormalize(lightdir);
2051 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2052 VectorNormalize(eyedir);
2053 VectorAdd(lightdir, eyedir, halfdir);
2054 // the cubemap normalizes this for us
2055 out3f[0] = DotProduct(svector3f, halfdir);
2056 out3f[1] = DotProduct(tvector3f, halfdir);
2057 out3f[2] = DotProduct(normal3f, halfdir);
2061 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)
2063 // used to display how many times a surface is lit for level design purposes
2064 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2067 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)
2069 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2070 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2071 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2072 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2074 R_Mesh_ColorPointer(NULL, 0, 0);
2075 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2076 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2077 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2078 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2079 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2080 if (rsurface.texture->backgroundcurrentskinframe)
2082 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2083 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2084 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2085 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2087 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2088 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2089 if(rsurface.texture->colormapping)
2091 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2092 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2094 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2095 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2096 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2097 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2098 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2099 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2101 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2103 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2104 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2106 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2110 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)
2112 // shared final code for all the dot3 layers
2114 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2115 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2117 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2118 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2122 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)
2125 // colorscale accounts for how much we multiply the brightness
2128 // mult is how many times the final pass of the lighting will be
2129 // performed to get more brightness than otherwise possible.
2131 // Limit mult to 64 for sanity sake.
2133 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2135 // 3 3D combine path (Geforce3, Radeon 8500)
2136 memset(&m, 0, sizeof(m));
2137 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2138 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2139 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2140 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2141 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2142 m.tex[1] = R_GetTexture(basetexture);
2143 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2144 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2145 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2146 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2147 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2148 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2149 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2150 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2151 m.texmatrix[2] = rsurface.entitytolight;
2152 GL_BlendFunc(GL_ONE, GL_ONE);
2154 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2156 // 2 3D combine path (Geforce3, original Radeon)
2157 memset(&m, 0, sizeof(m));
2158 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2159 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2160 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2161 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2162 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2163 m.tex[1] = R_GetTexture(basetexture);
2164 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2165 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2166 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2167 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2168 GL_BlendFunc(GL_ONE, GL_ONE);
2170 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2172 // 4 2D combine path (Geforce3, Radeon 8500)
2173 memset(&m, 0, sizeof(m));
2174 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2175 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2176 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2177 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2178 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2179 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2180 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2181 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2182 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2183 m.texmatrix[1] = rsurface.entitytoattenuationz;
2184 m.tex[2] = R_GetTexture(basetexture);
2185 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2186 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2187 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2188 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2189 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2191 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2192 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2193 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2194 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2195 m.texmatrix[3] = rsurface.entitytolight;
2197 GL_BlendFunc(GL_ONE, GL_ONE);
2199 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2201 // 3 2D combine path (Geforce3, original Radeon)
2202 memset(&m, 0, sizeof(m));
2203 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2204 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2205 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2206 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2207 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2208 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2209 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2210 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2211 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2212 m.texmatrix[1] = rsurface.entitytoattenuationz;
2213 m.tex[2] = R_GetTexture(basetexture);
2214 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2215 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2216 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2217 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2218 GL_BlendFunc(GL_ONE, GL_ONE);
2222 // 2/2/2 2D combine path (any dot3 card)
2223 memset(&m, 0, sizeof(m));
2224 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2225 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2226 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2227 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2228 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2229 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2230 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2231 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2232 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2233 m.texmatrix[1] = rsurface.entitytoattenuationz;
2234 R_Mesh_TextureState(&m);
2235 GL_ColorMask(0,0,0,1);
2236 GL_BlendFunc(GL_ONE, GL_ZERO);
2237 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2240 memset(&m, 0, sizeof(m));
2241 m.tex[0] = R_GetTexture(basetexture);
2242 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2243 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2244 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2245 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2246 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2248 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2249 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2250 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2251 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2252 m.texmatrix[1] = rsurface.entitytolight;
2254 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2256 // this final code is shared
2257 R_Mesh_TextureState(&m);
2258 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);
2261 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)
2264 // colorscale accounts for how much we multiply the brightness
2267 // mult is how many times the final pass of the lighting will be
2268 // performed to get more brightness than otherwise possible.
2270 // Limit mult to 64 for sanity sake.
2272 // generate normalization cubemap texcoords
2273 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2274 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2276 // 3/2 3D combine path (Geforce3, Radeon 8500)
2277 memset(&m, 0, sizeof(m));
2278 m.tex[0] = R_GetTexture(normalmaptexture);
2279 m.texcombinergb[0] = GL_REPLACE;
2280 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2281 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2282 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2283 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2284 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2285 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2286 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2287 m.pointer_texcoord_bufferobject[1] = 0;
2288 m.pointer_texcoord_bufferoffset[1] = 0;
2289 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2290 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2291 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2292 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2293 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2294 R_Mesh_TextureState(&m);
2295 GL_ColorMask(0,0,0,1);
2296 GL_BlendFunc(GL_ONE, GL_ZERO);
2297 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2300 memset(&m, 0, sizeof(m));
2301 m.tex[0] = R_GetTexture(basetexture);
2302 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2303 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2304 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2305 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2306 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2308 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2309 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2310 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2311 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2312 m.texmatrix[1] = rsurface.entitytolight;
2314 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2316 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2318 // 1/2/2 3D combine path (original Radeon)
2319 memset(&m, 0, sizeof(m));
2320 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2321 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2322 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2323 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2324 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2325 R_Mesh_TextureState(&m);
2326 GL_ColorMask(0,0,0,1);
2327 GL_BlendFunc(GL_ONE, GL_ZERO);
2328 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2331 memset(&m, 0, sizeof(m));
2332 m.tex[0] = R_GetTexture(normalmaptexture);
2333 m.texcombinergb[0] = GL_REPLACE;
2334 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2335 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2336 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2337 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2338 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2339 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2340 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2341 m.pointer_texcoord_bufferobject[1] = 0;
2342 m.pointer_texcoord_bufferoffset[1] = 0;
2343 R_Mesh_TextureState(&m);
2344 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2345 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2348 memset(&m, 0, sizeof(m));
2349 m.tex[0] = R_GetTexture(basetexture);
2350 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2351 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2352 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2353 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2354 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2356 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2357 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2358 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2359 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2360 m.texmatrix[1] = rsurface.entitytolight;
2362 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2364 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2366 // 2/2 3D combine path (original Radeon)
2367 memset(&m, 0, sizeof(m));
2368 m.tex[0] = R_GetTexture(normalmaptexture);
2369 m.texcombinergb[0] = GL_REPLACE;
2370 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2371 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2372 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2373 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2374 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2375 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2376 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2377 m.pointer_texcoord_bufferobject[1] = 0;
2378 m.pointer_texcoord_bufferoffset[1] = 0;
2379 R_Mesh_TextureState(&m);
2380 GL_ColorMask(0,0,0,1);
2381 GL_BlendFunc(GL_ONE, GL_ZERO);
2382 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2385 memset(&m, 0, sizeof(m));
2386 m.tex[0] = R_GetTexture(basetexture);
2387 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2388 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2389 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2390 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2391 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2392 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2393 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2394 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2395 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2396 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2398 else if (r_textureunits.integer >= 4)
2400 // 4/2 2D combine path (Geforce3, Radeon 8500)
2401 memset(&m, 0, sizeof(m));
2402 m.tex[0] = R_GetTexture(normalmaptexture);
2403 m.texcombinergb[0] = GL_REPLACE;
2404 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2405 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2406 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2407 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2408 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2409 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2410 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2411 m.pointer_texcoord_bufferobject[1] = 0;
2412 m.pointer_texcoord_bufferoffset[1] = 0;
2413 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2414 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2415 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2416 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2417 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2418 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2419 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2420 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2421 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2422 m.texmatrix[3] = rsurface.entitytoattenuationz;
2423 R_Mesh_TextureState(&m);
2424 GL_ColorMask(0,0,0,1);
2425 GL_BlendFunc(GL_ONE, GL_ZERO);
2426 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2429 memset(&m, 0, sizeof(m));
2430 m.tex[0] = R_GetTexture(basetexture);
2431 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2432 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2433 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2434 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2435 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2437 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2438 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2439 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2440 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2441 m.texmatrix[1] = rsurface.entitytolight;
2443 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2447 // 2/2/2 2D combine path (any dot3 card)
2448 memset(&m, 0, sizeof(m));
2449 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2450 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2451 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2452 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2453 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2454 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2455 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2456 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2457 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2458 m.texmatrix[1] = rsurface.entitytoattenuationz;
2459 R_Mesh_TextureState(&m);
2460 GL_ColorMask(0,0,0,1);
2461 GL_BlendFunc(GL_ONE, GL_ZERO);
2462 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2465 memset(&m, 0, sizeof(m));
2466 m.tex[0] = R_GetTexture(normalmaptexture);
2467 m.texcombinergb[0] = GL_REPLACE;
2468 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2469 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2470 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2471 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2472 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2473 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2474 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2475 m.pointer_texcoord_bufferobject[1] = 0;
2476 m.pointer_texcoord_bufferoffset[1] = 0;
2477 R_Mesh_TextureState(&m);
2478 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2479 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2482 memset(&m, 0, sizeof(m));
2483 m.tex[0] = R_GetTexture(basetexture);
2484 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2485 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2486 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2487 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2488 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2490 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2491 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2492 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2493 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2494 m.texmatrix[1] = rsurface.entitytolight;
2496 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2498 // this final code is shared
2499 R_Mesh_TextureState(&m);
2500 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);
2503 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)
2505 float glossexponent;
2507 // FIXME: detect blendsquare!
2508 //if (!gl_support_blendsquare)
2511 // generate normalization cubemap texcoords
2512 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2513 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2515 // 2/0/0/1/2 3D combine blendsquare path
2516 memset(&m, 0, sizeof(m));
2517 m.tex[0] = R_GetTexture(normalmaptexture);
2518 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2519 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2520 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2521 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2522 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2523 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2524 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2525 m.pointer_texcoord_bufferobject[1] = 0;
2526 m.pointer_texcoord_bufferoffset[1] = 0;
2527 R_Mesh_TextureState(&m);
2528 GL_ColorMask(0,0,0,1);
2529 // this squares the result
2530 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2531 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2533 // second and third pass
2534 R_Mesh_ResetTextureState();
2535 // square alpha in framebuffer a few times to make it shiny
2536 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2537 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2538 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2541 memset(&m, 0, sizeof(m));
2542 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2543 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2544 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2545 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2546 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2547 R_Mesh_TextureState(&m);
2548 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2549 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2552 memset(&m, 0, sizeof(m));
2553 m.tex[0] = R_GetTexture(glosstexture);
2554 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2555 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2556 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2557 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2558 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2560 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2561 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2562 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2563 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2564 m.texmatrix[1] = rsurface.entitytolight;
2566 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2568 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2570 // 2/0/0/2 3D combine blendsquare path
2571 memset(&m, 0, sizeof(m));
2572 m.tex[0] = R_GetTexture(normalmaptexture);
2573 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2574 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2575 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2576 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2577 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2578 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2579 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2580 m.pointer_texcoord_bufferobject[1] = 0;
2581 m.pointer_texcoord_bufferoffset[1] = 0;
2582 R_Mesh_TextureState(&m);
2583 GL_ColorMask(0,0,0,1);
2584 // this squares the result
2585 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2586 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2588 // second and third pass
2589 R_Mesh_ResetTextureState();
2590 // square alpha in framebuffer a few times to make it shiny
2591 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2592 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2593 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2596 memset(&m, 0, sizeof(m));
2597 m.tex[0] = R_GetTexture(glosstexture);
2598 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2599 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2600 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2601 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2602 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2603 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2604 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2605 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2606 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2607 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2611 // 2/0/0/2/2 2D combine blendsquare path
2612 memset(&m, 0, sizeof(m));
2613 m.tex[0] = R_GetTexture(normalmaptexture);
2614 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2615 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2616 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2617 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2618 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2619 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2620 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2621 m.pointer_texcoord_bufferobject[1] = 0;
2622 m.pointer_texcoord_bufferoffset[1] = 0;
2623 R_Mesh_TextureState(&m);
2624 GL_ColorMask(0,0,0,1);
2625 // this squares the result
2626 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2627 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2629 // second and third pass
2630 R_Mesh_ResetTextureState();
2631 // square alpha in framebuffer a few times to make it shiny
2632 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2633 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2634 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2637 memset(&m, 0, sizeof(m));
2638 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2639 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2640 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2641 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2642 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2643 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2644 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2645 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2646 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2647 m.texmatrix[1] = rsurface.entitytoattenuationz;
2648 R_Mesh_TextureState(&m);
2649 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2650 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2653 memset(&m, 0, sizeof(m));
2654 m.tex[0] = R_GetTexture(glosstexture);
2655 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2656 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2658 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2659 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2661 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2662 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2663 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2664 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2665 m.texmatrix[1] = rsurface.entitytolight;
2667 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2669 // this final code is shared
2670 R_Mesh_TextureState(&m);
2671 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);
2674 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)
2676 // ARB path (any Geforce, any Radeon)
2677 qboolean doambient = ambientscale > 0;
2678 qboolean dodiffuse = diffusescale > 0;
2679 qboolean dospecular = specularscale > 0;
2680 if (!doambient && !dodiffuse && !dospecular)
2682 R_Mesh_ColorPointer(NULL, 0, 0);
2684 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2686 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2690 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2692 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2697 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2699 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2702 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2705 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2712 int newnumtriangles;
2716 int maxtriangles = 4096;
2717 int newelements[4096*3];
2718 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2719 for (renders = 0;renders < 64;renders++)
2724 newnumtriangles = 0;
2726 // due to low fillrate on the cards this vertex lighting path is
2727 // designed for, we manually cull all triangles that do not
2728 // contain a lit vertex
2729 // this builds batches of triangles from multiple surfaces and
2730 // renders them at once
2731 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2733 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2735 if (newnumtriangles)
2737 newfirstvertex = min(newfirstvertex, e[0]);
2738 newlastvertex = max(newlastvertex, e[0]);
2742 newfirstvertex = e[0];
2743 newlastvertex = e[0];
2745 newfirstvertex = min(newfirstvertex, e[1]);
2746 newlastvertex = max(newlastvertex, e[1]);
2747 newfirstvertex = min(newfirstvertex, e[2]);
2748 newlastvertex = max(newlastvertex, e[2]);
2754 if (newnumtriangles >= maxtriangles)
2756 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2757 newnumtriangles = 0;
2763 if (newnumtriangles >= 1)
2765 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2768 // if we couldn't find any lit triangles, exit early
2771 // now reduce the intensity for the next overbright pass
2772 // we have to clamp to 0 here incase the drivers have improper
2773 // handling of negative colors
2774 // (some old drivers even have improper handling of >1 color)
2776 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2778 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2780 c[0] = max(0, c[0] - 1);
2781 c[1] = max(0, c[1] - 1);
2782 c[2] = max(0, c[2] - 1);
2794 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)
2796 // OpenGL 1.1 path (anything)
2797 float ambientcolorbase[3], diffusecolorbase[3];
2798 float ambientcolorpants[3], diffusecolorpants[3];
2799 float ambientcolorshirt[3], diffusecolorshirt[3];
2801 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2802 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2803 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2804 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2805 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2806 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2807 memset(&m, 0, sizeof(m));
2808 m.tex[0] = R_GetTexture(basetexture);
2809 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2810 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2811 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2812 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2813 if (r_textureunits.integer >= 2)
2816 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2817 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2818 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2819 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2820 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2821 if (r_textureunits.integer >= 3)
2823 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2824 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2825 m.texmatrix[2] = rsurface.entitytoattenuationz;
2826 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2827 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2828 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2831 R_Mesh_TextureState(&m);
2832 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2833 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2836 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2837 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2841 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2842 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2846 extern cvar_t gl_lightmaps;
2847 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)
2849 float ambientscale, diffusescale, specularscale;
2850 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2852 // calculate colors to render this texture with
2853 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2854 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2855 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2856 ambientscale = rsurface.rtlight->ambientscale;
2857 diffusescale = rsurface.rtlight->diffusescale;
2858 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2859 if (!r_shadow_usenormalmap.integer)
2861 ambientscale += 1.0f * diffusescale;
2865 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2867 RSurf_SetupDepthAndCulling();
2868 nmap = rsurface.texture->currentskinframe->nmap;
2869 if (gl_lightmaps.integer)
2870 nmap = r_texture_blanknormalmap;
2871 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2873 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2874 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2877 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2878 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2879 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2882 VectorClear(lightcolorpants);
2885 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2886 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2887 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2890 VectorClear(lightcolorshirt);
2891 switch (r_shadow_rendermode)
2893 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2894 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2895 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);
2897 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2898 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);
2900 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2901 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);
2903 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2904 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);
2907 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2913 switch (r_shadow_rendermode)
2915 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2916 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2917 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);
2919 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2920 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);
2922 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
2923 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);
2925 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2926 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);
2929 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2935 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)
2937 matrix4x4_t tempmatrix = *matrix;
2938 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2940 // if this light has been compiled before, free the associated data
2941 R_RTLight_Uncompile(rtlight);
2943 // clear it completely to avoid any lingering data
2944 memset(rtlight, 0, sizeof(*rtlight));
2946 // copy the properties
2947 rtlight->matrix_lighttoworld = tempmatrix;
2948 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2949 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2950 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2951 VectorCopy(color, rtlight->color);
2952 rtlight->cubemapname[0] = 0;
2953 if (cubemapname && cubemapname[0])
2954 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2955 rtlight->shadow = shadow;
2956 rtlight->corona = corona;
2957 rtlight->style = style;
2958 rtlight->isstatic = isstatic;
2959 rtlight->coronasizescale = coronasizescale;
2960 rtlight->ambientscale = ambientscale;
2961 rtlight->diffusescale = diffusescale;
2962 rtlight->specularscale = specularscale;
2963 rtlight->flags = flags;
2965 // compute derived data
2966 //rtlight->cullradius = rtlight->radius;
2967 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2968 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2969 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2970 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2971 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2972 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2973 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2976 // compiles rtlight geometry
2977 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2978 void R_RTLight_Compile(rtlight_t *rtlight)
2981 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2982 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2983 entity_render_t *ent = r_refdef.scene.worldentity;
2984 dp_model_t *model = r_refdef.scene.worldmodel;
2985 unsigned char *data;
2988 // compile the light
2989 rtlight->compiled = true;
2990 rtlight->static_numleafs = 0;
2991 rtlight->static_numleafpvsbytes = 0;
2992 rtlight->static_leaflist = NULL;
2993 rtlight->static_leafpvs = NULL;
2994 rtlight->static_numsurfaces = 0;
2995 rtlight->static_surfacelist = NULL;
2996 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2997 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2998 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2999 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3000 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3001 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3003 if (model && model->GetLightInfo)
3005 // this variable must be set for the CompileShadowVolume code
3006 r_shadow_compilingrtlight = rtlight;
3007 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);
3008 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);
3009 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3010 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3011 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3012 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3013 rtlight->static_numsurfaces = numsurfaces;
3014 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3015 rtlight->static_numleafs = numleafs;
3016 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3017 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3018 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3019 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3020 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3021 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3022 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3023 if (rtlight->static_numsurfaces)
3024 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3025 if (rtlight->static_numleafs)
3026 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3027 if (rtlight->static_numleafpvsbytes)
3028 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3029 if (rtlight->static_numshadowtrispvsbytes)
3030 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3031 if (rtlight->static_numlighttrispvsbytes)
3032 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3033 if (model->CompileShadowVolume && rtlight->shadow)
3034 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3035 // now we're done compiling the rtlight
3036 r_shadow_compilingrtlight = NULL;
3040 // use smallest available cullradius - box radius or light radius
3041 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3042 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3044 shadowzpasstris = 0;
3045 if (rtlight->static_meshchain_shadow_zpass)
3046 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3047 shadowzpasstris += mesh->numtriangles;
3049 shadowzfailtris = 0;
3050 if (rtlight->static_meshchain_shadow_zfail)
3051 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3052 shadowzfailtris += mesh->numtriangles;
3055 if (rtlight->static_numlighttrispvsbytes)
3056 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3057 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3061 if (rtlight->static_numlighttrispvsbytes)
3062 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3063 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3066 if (developer.integer >= 10)
3067 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);
3070 void R_RTLight_Uncompile(rtlight_t *rtlight)
3072 if (rtlight->compiled)
3074 if (rtlight->static_meshchain_shadow_zpass)
3075 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3076 rtlight->static_meshchain_shadow_zpass = NULL;
3077 if (rtlight->static_meshchain_shadow_zfail)
3078 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3079 rtlight->static_meshchain_shadow_zfail = NULL;
3080 // these allocations are grouped
3081 if (rtlight->static_surfacelist)
3082 Mem_Free(rtlight->static_surfacelist);
3083 rtlight->static_numleafs = 0;
3084 rtlight->static_numleafpvsbytes = 0;
3085 rtlight->static_leaflist = NULL;
3086 rtlight->static_leafpvs = NULL;
3087 rtlight->static_numsurfaces = 0;
3088 rtlight->static_surfacelist = NULL;
3089 rtlight->static_numshadowtrispvsbytes = 0;
3090 rtlight->static_shadowtrispvs = NULL;
3091 rtlight->static_numlighttrispvsbytes = 0;
3092 rtlight->static_lighttrispvs = NULL;
3093 rtlight->compiled = false;
3097 void R_Shadow_UncompileWorldLights(void)
3101 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3102 for (lightindex = 0;lightindex < range;lightindex++)
3104 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3107 R_RTLight_Uncompile(&light->rtlight);
3111 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3115 // reset the count of frustum planes
3116 // see rsurface.rtlight_frustumplanes definition for how much this array
3118 rsurface.rtlight_numfrustumplanes = 0;
3120 // haven't implemented a culling path for ortho rendering
3121 if (!r_refdef.view.useperspective)
3123 // check if the light is on screen and copy the 4 planes if it is
3124 for (i = 0;i < 4;i++)
3125 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3128 for (i = 0;i < 4;i++)
3129 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3134 // generate a deformed frustum that includes the light origin, this is
3135 // used to cull shadow casting surfaces that can not possibly cast a
3136 // shadow onto the visible light-receiving surfaces, which can be a
3139 // if the light origin is onscreen the result will be 4 planes exactly
3140 // if the light origin is offscreen on only one axis the result will
3141 // be exactly 5 planes (split-side case)
3142 // if the light origin is offscreen on two axes the result will be
3143 // exactly 4 planes (stretched corner case)
3144 for (i = 0;i < 4;i++)
3146 // quickly reject standard frustum planes that put the light
3147 // origin outside the frustum
3148 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3151 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3153 // if all the standard frustum planes were accepted, the light is onscreen
3154 // otherwise we need to generate some more planes below...
3155 if (rsurface.rtlight_numfrustumplanes < 4)
3157 // at least one of the stock frustum planes failed, so we need to
3158 // create one or two custom planes to enclose the light origin
3159 for (i = 0;i < 4;i++)
3161 // create a plane using the view origin and light origin, and a
3162 // single point from the frustum corner set
3163 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3164 VectorNormalize(plane.normal);
3165 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3166 // see if this plane is backwards and flip it if so
3167 for (j = 0;j < 4;j++)
3168 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3172 VectorNegate(plane.normal, plane.normal);
3174 // flipped plane, test again to see if it is now valid
3175 for (j = 0;j < 4;j++)
3176 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3178 // if the plane is still not valid, then it is dividing the
3179 // frustum and has to be rejected
3183 // we have created a valid plane, compute extra info
3184 PlaneClassify(&plane);
3186 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3188 // if we've found 5 frustum planes then we have constructed a
3189 // proper split-side case and do not need to keep searching for
3190 // planes to enclose the light origin
3191 if (rsurface.rtlight_numfrustumplanes == 5)
3199 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3201 plane = rsurface.rtlight_frustumplanes[i];
3202 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));
3207 // now add the light-space box planes if the light box is rotated, as any
3208 // caster outside the oriented light box is irrelevant (even if it passed
3209 // the worldspace light box, which is axial)
3210 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3212 for (i = 0;i < 6;i++)
3216 v[i >> 1] = (i & 1) ? -1 : 1;
3217 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3218 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3219 plane.dist = VectorNormalizeLength(plane.normal);
3220 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3221 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3227 // add the world-space reduced box planes
3228 for (i = 0;i < 6;i++)
3230 VectorClear(plane.normal);
3231 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3232 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3233 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3242 // reduce all plane distances to tightly fit the rtlight cull box, which
3244 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3245 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3246 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3247 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3248 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3249 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3250 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3251 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3252 oldnum = rsurface.rtlight_numfrustumplanes;
3253 rsurface.rtlight_numfrustumplanes = 0;
3254 for (j = 0;j < oldnum;j++)
3256 // find the nearest point on the box to this plane
3257 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3258 for (i = 1;i < 8;i++)
3260 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3261 if (bestdist > dist)
3264 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);
3265 // if the nearest point is near or behind the plane, we want this
3266 // plane, otherwise the plane is useless as it won't cull anything
3267 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3269 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3270 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3277 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3282 int surfacelistindex;
3283 msurface_t *surface;
3285 RSurf_ActiveWorldEntity();
3286 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3288 if (r_refdef.scene.worldentity->model)
3289 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3290 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3294 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3297 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3298 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3299 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3300 for (;mesh;mesh = mesh->next)
3302 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3303 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3304 GL_LockArrays(0, mesh->numverts);
3305 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3307 // increment stencil if frontface is infront of depthbuffer
3308 GL_CullFace(r_refdef.view.cullface_back);
3309 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3310 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3311 // decrement stencil if backface is infront of depthbuffer
3312 GL_CullFace(r_refdef.view.cullface_front);
3313 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3315 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3317 // decrement stencil if backface is behind depthbuffer
3318 GL_CullFace(r_refdef.view.cullface_front);
3319 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3320 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3321 // increment stencil if frontface is behind depthbuffer
3322 GL_CullFace(r_refdef.view.cullface_back);
3323 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3325 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3326 GL_LockArrays(0, 0);
3330 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3332 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3333 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3335 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3336 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3337 if (CHECKPVSBIT(trispvs, t))
3338 shadowmarklist[numshadowmark++] = t;
3340 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);
3342 else if (numsurfaces)
3343 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3345 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3348 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3350 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3351 vec_t relativeshadowradius;
3352 RSurf_ActiveModelEntity(ent, false, false);
3353 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3354 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3355 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3356 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3357 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3358 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3359 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3360 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3361 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3362 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3364 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3365 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3368 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3370 // set up properties for rendering light onto this entity
3371 RSurf_ActiveModelEntity(ent, true, true);
3372 GL_AlphaTest(false);
3373 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3374 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3375 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3376 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3377 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3378 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3381 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3383 if (!r_refdef.scene.worldmodel->DrawLight)
3386 // set up properties for rendering light onto this entity
3387 RSurf_ActiveWorldEntity();
3388 GL_AlphaTest(false);
3389 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3390 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3391 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3392 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3393 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3394 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3396 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3398 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3401 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3403 dp_model_t *model = ent->model;
3404 if (!model->DrawLight)
3407 R_Shadow_SetupEntityLight(ent);
3409 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3411 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3415 {{ 0, 0, 0}, "px", true, true, true},
3416 {{ 0, 90, 0}, "py", false, true, false},
3417 {{ 0, 180, 0}, "nx", false, false, true},
3418 {{ 0, 270, 0}, "ny", true, false, false},
3419 {{-90, 180, 0}, "pz", false, false, true},
3420 {{ 90, 180, 0}, "nz", false, false, true}
3423 static const double shadowviewmat16[6][4][4] =
3463 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3467 int numleafs, numsurfaces;
3468 int *leaflist, *surfacelist;
3469 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3470 int numlightentities;
3471 int numlightentities_noselfshadow;
3472 int numshadowentities;
3473 int numshadowentities_noselfshadow;
3474 static entity_render_t *lightentities[MAX_EDICTS];
3475 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3476 static entity_render_t *shadowentities[MAX_EDICTS];
3477 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3478 vec3_t nearestpoint;
3480 qboolean castshadows;
3483 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3484 // skip lights that are basically invisible (color 0 0 0)
3485 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3488 // loading is done before visibility checks because loading should happen
3489 // all at once at the start of a level, not when it stalls gameplay.
3490 // (especially important to benchmarks)
3492 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3493 R_RTLight_Compile(rtlight);
3495 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3497 // look up the light style value at this time
3498 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3499 VectorScale(rtlight->color, f, rtlight->currentcolor);
3501 if (rtlight->selected)
3503 f = 2 + sin(realtime * M_PI * 4.0);
3504 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3508 // if lightstyle is currently off, don't draw the light
3509 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3512 // if the light box is offscreen, skip it
3513 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3516 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3517 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3519 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3521 // compiled light, world available and can receive realtime lighting
3522 // retrieve leaf information
3523 numleafs = rtlight->static_numleafs;
3524 leaflist = rtlight->static_leaflist;
3525 leafpvs = rtlight->static_leafpvs;
3526 numsurfaces = rtlight->static_numsurfaces;
3527 surfacelist = rtlight->static_surfacelist;
3528 shadowtrispvs = rtlight->static_shadowtrispvs;
3529 lighttrispvs = rtlight->static_lighttrispvs;
3531 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3533 // dynamic light, world available and can receive realtime lighting
3534 // calculate lit surfaces and leafs
3535 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);
3536 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);
3537 leaflist = r_shadow_buffer_leaflist;
3538 leafpvs = r_shadow_buffer_leafpvs;
3539 surfacelist = r_shadow_buffer_surfacelist;
3540 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3541 lighttrispvs = r_shadow_buffer_lighttrispvs;
3542 // if the reduced leaf bounds are offscreen, skip it
3543 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3554 shadowtrispvs = NULL;
3555 lighttrispvs = NULL;
3557 // check if light is illuminating any visible leafs
3560 for (i = 0;i < numleafs;i++)
3561 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3566 // set up a scissor rectangle for this light
3567 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3570 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3572 // make a list of lit entities and shadow casting entities
3573 numlightentities = 0;
3574 numlightentities_noselfshadow = 0;
3575 numshadowentities = 0;
3576 numshadowentities_noselfshadow = 0;
3577 // add dynamic entities that are lit by the light
3578 if (r_drawentities.integer)
3580 for (i = 0;i < r_refdef.scene.numentities;i++)
3583 entity_render_t *ent = r_refdef.scene.entities[i];
3585 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3587 // skip the object entirely if it is not within the valid
3588 // shadow-casting region (which includes the lit region)
3589 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3591 if (!(model = ent->model))
3593 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3595 // this entity wants to receive light, is visible, and is
3596 // inside the light box
3597 // TODO: check if the surfaces in the model can receive light
3598 // so now check if it's in a leaf seen by the light
3599 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))
3601 if (ent->flags & RENDER_NOSELFSHADOW)
3602 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3604 lightentities[numlightentities++] = ent;
3605 // since it is lit, it probably also casts a shadow...
3606 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3607 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3608 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3610 // note: exterior models without the RENDER_NOSELFSHADOW
3611 // flag still create a RENDER_NOSELFSHADOW shadow but
3612 // are lit normally, this means that they are
3613 // self-shadowing but do not shadow other
3614 // RENDER_NOSELFSHADOW entities such as the gun
3615 // (very weird, but keeps the player shadow off the gun)
3616 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3617 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3619 shadowentities[numshadowentities++] = ent;
3622 else if (ent->flags & RENDER_SHADOW)
3624 // this entity is not receiving light, but may still need to
3626 // TODO: check if the surfaces in the model can cast shadow
3627 // now check if it is in a leaf seen by the light
3628 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))
3630 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3631 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3632 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3634 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3635 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3637 shadowentities[numshadowentities++] = ent;
3643 // return if there's nothing at all to light
3644 if (!numlightentities && !numsurfaces)
3647 // don't let sound skip if going slow
3648 if (r_refdef.scene.extraupdate)
3651 // make this the active rtlight for rendering purposes
3652 R_Shadow_RenderMode_ActiveLight(rtlight);
3653 // count this light in the r_speeds
3654 r_refdef.stats.lights++;
3656 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3658 // optionally draw visible shape of the shadow volumes
3659 // for performance analysis by level designers
3660 R_Shadow_RenderMode_VisibleShadowVolumes();
3662 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3663 for (i = 0;i < numshadowentities;i++)
3664 R_Shadow_DrawEntityShadow(shadowentities[i]);
3665 for (i = 0;i < numshadowentities_noselfshadow;i++)
3666 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3669 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3671 // optionally draw the illuminated areas
3672 // for performance analysis by level designers
3673 R_Shadow_RenderMode_VisibleLighting(false, false);
3675 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3676 for (i = 0;i < numlightentities;i++)
3677 R_Shadow_DrawEntityLight(lightentities[i]);
3678 for (i = 0;i < numlightentities_noselfshadow;i++)
3679 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3682 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3684 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3685 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3686 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3687 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3688 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3689 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3691 if (castshadows && r_shadow_shadowmapping.integer >= 1 && r_shadow_shadowmapping.integer <= 3 && r_glsl.integer && gl_support_fragment_shader)
3696 r_shadow_shadowmaplod = 0;
3697 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3698 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3699 r_shadow_shadowmaplod = i;
3702 if (r_shadow_shadowmapping.integer == 3)
3703 size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod;
3704 size = bound(1, size, 2048);
3706 Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3708 // render shadow casters into 6 sided depth texture
3709 for (side = 0;side < 6;side++)
3711 R_Shadow_RenderMode_ShadowMap(side, true, size);
3713 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3714 for (i = 0;i < numshadowentities;i++)
3715 R_Shadow_DrawEntityShadow(shadowentities[i]);
3718 if (numlightentities_noselfshadow)
3720 // render lighting using the depth texture as shadowmap
3721 // draw lighting in the unmasked areas
3722 R_Shadow_RenderMode_Lighting(false, false, true);
3723 for (i = 0;i < numlightentities_noselfshadow;i++)
3724 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3727 // render shadow casters into 6 sided depth texture
3728 for (side = 0;side < 6;side++)
3730 R_Shadow_RenderMode_ShadowMap(side, false, size);
3731 for (i = 0;i < numshadowentities_noselfshadow;i++)
3732 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3734 if (r_shadow_shadowmapping.integer == 1)
3736 int w = R_TextureWidth(r_shadow_shadowmap2dtexture);
3737 int h = R_TextureHeight(r_shadow_shadowmap2dtexture);
3738 static int once = true;
3741 unsigned char *blah = Z_Malloc(w*h*4);
3742 qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR
3743 FS_WriteFile("testshadowmap.bin", blah, w*h*4);
3751 // render lighting using the depth texture as shadowmap
3752 // draw lighting in the unmasked areas
3753 R_Shadow_RenderMode_Lighting(false, false, true);
3754 // draw lighting in the unmasked areas
3756 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3757 for (i = 0;i < numlightentities;i++)
3758 R_Shadow_DrawEntityLight(lightentities[i]);
3760 else if (castshadows && gl_stencil)
3762 // draw stencil shadow volumes to mask off pixels that are in shadow
3763 // so that they won't receive lighting
3764 R_Shadow_ClearStencil();
3766 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3767 for (i = 0;i < numshadowentities;i++)
3768 R_Shadow_DrawEntityShadow(shadowentities[i]);
3769 if (numlightentities_noselfshadow)
3771 // draw lighting in the unmasked areas
3772 R_Shadow_RenderMode_Lighting(true, false, false);
3773 for (i = 0;i < numlightentities_noselfshadow;i++)
3774 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3776 // optionally draw the illuminated areas
3777 // for performance analysis by level designers
3778 if (r_showlighting.integer && r_refdef.view.showdebug)
3780 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3781 for (i = 0;i < numlightentities_noselfshadow;i++)
3782 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3785 for (i = 0;i < numshadowentities_noselfshadow;i++)
3786 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3788 if (numsurfaces + numlightentities)
3790 // draw lighting in the unmasked areas
3791 R_Shadow_RenderMode_Lighting(true, false, false);
3793 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3794 for (i = 0;i < numlightentities;i++)
3795 R_Shadow_DrawEntityLight(lightentities[i]);
3800 if (numsurfaces + numlightentities)
3802 // draw lighting in the unmasked areas
3803 R_Shadow_RenderMode_Lighting(false, false, false);
3805 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3806 for (i = 0;i < numlightentities;i++)
3807 R_Shadow_DrawEntityLight(lightentities[i]);
3808 for (i = 0;i < numlightentities_noselfshadow;i++)
3809 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3814 void R_Shadow_DrawLightSprites(void);
3815 void R_ShadowVolumeLighting(qboolean visible)
3823 if (r_editlights.integer)
3824 R_Shadow_DrawLightSprites();
3826 R_Shadow_RenderMode_Begin();
3828 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3829 if (r_shadow_debuglight.integer >= 0)
3831 lightindex = r_shadow_debuglight.integer;
3832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3833 if (light && (light->flags & flag))
3834 R_DrawRTLight(&light->rtlight, visible);
3838 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3839 for (lightindex = 0;lightindex < range;lightindex++)
3841 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3842 if (light && (light->flags & flag))
3843 R_DrawRTLight(&light->rtlight, visible);
3846 if (r_refdef.scene.rtdlight)
3847 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3848 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3850 R_Shadow_RenderMode_End();
3853 extern void R_SetupView(qboolean allowwaterclippingplane);
3854 extern cvar_t r_shadows;
3855 extern cvar_t r_shadows_darken;
3856 extern cvar_t r_shadows_drawafterrtlightning;
3857 extern cvar_t r_shadows_castfrombmodels;
3858 extern cvar_t r_shadows_throwdistance;
3859 extern cvar_t r_shadows_throwdirection;
3860 void R_DrawModelShadows(void)
3863 float relativethrowdistance;
3864 entity_render_t *ent;
3865 vec3_t relativelightorigin;
3866 vec3_t relativelightdirection;
3867 vec3_t relativeshadowmins, relativeshadowmaxs;
3868 vec3_t tmp, shadowdir;
3870 r_viewport_t viewport;
3872 if (!r_drawentities.integer || !gl_stencil)
3876 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3878 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3880 if (gl_ext_separatestencil.integer)
3882 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
3883 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
3885 else if (gl_ext_stenciltwoside.integer)
3887 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
3888 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
3892 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
3893 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
3897 if (r_shadows.integer == 2)
3899 Math_atov(r_shadows_throwdirection.string, shadowdir);
3900 VectorNormalize(shadowdir);
3903 R_Shadow_ClearStencil();
3905 for (i = 0;i < r_refdef.scene.numentities;i++)
3907 ent = r_refdef.scene.entities[i];
3909 // cast shadows from anything of the map (submodels are optional)
3910 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
3912 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
3913 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
3914 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
3915 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
3916 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
3919 if(ent->entitynumber != 0)
3921 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
3922 int entnum, entnum2, recursion;
3923 entnum = entnum2 = ent->entitynumber;
3924 for(recursion = 32; recursion > 0; --recursion)
3926 entnum2 = cl.entities[entnum].state_current.tagentity;
3927 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
3932 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
3934 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
3935 // transform into modelspace of OUR entity
3936 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
3937 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
3940 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3943 VectorNegate(ent->modellight_lightdir, relativelightdirection);
3946 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
3947 RSurf_ActiveModelEntity(ent, false, false);
3948 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3949 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3953 // not really the right mode, but this will disable any silly stencil features
3954 R_Shadow_RenderMode_VisibleLighting(true, true);
3956 // vertex coordinates for a quad that covers the screen exactly
3957 vertex3f[0] = 0;vertex3f[1] = 0;vertex3f[2] = 0;
3958 vertex3f[3] = 1;vertex3f[4] = 0;vertex3f[5] = 0;
3959 vertex3f[6] = 1;vertex3f[7] = 1;vertex3f[8] = 0;
3960 vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
3962 // set up ortho view for rendering this pass
3963 R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
3964 R_SetViewport(&viewport);
3965 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3966 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3967 GL_ScissorTest(true);
3968 R_Mesh_Matrix(&identitymatrix);
3969 R_Mesh_ResetTextureState();
3970 R_Mesh_VertexPointer(vertex3f, 0, 0);
3971 R_Mesh_ColorPointer(NULL, 0, 0);
3973 // set up a darkening blend on shadowed areas
3974 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3975 GL_DepthRange(0, 1);
3976 GL_DepthTest(false);
3977 GL_DepthMask(false);
3978 GL_PolygonOffset(0, 0);CHECKGLERROR
3979 GL_Color(0, 0, 0, r_shadows_darken.value);
3980 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3981 qglDepthFunc(GL_ALWAYS);CHECKGLERROR
3982 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
3983 qglStencilMask(~0);CHECKGLERROR
3984 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3985 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
3987 // apply the blend to the shadowed areas
3988 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3990 // restore the viewport
3991 R_SetViewport(&r_refdef.view.viewport);
3993 // restore other state to normal
3994 R_Shadow_RenderMode_End();
3997 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4000 vec3_t centerorigin;
4001 // if it's too close, skip it
4002 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4004 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4007 if (usequery && r_numqueries + 2 <= r_maxqueries)
4009 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4010 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4011 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4014 // 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
4015 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4016 qglDepthFunc(GL_ALWAYS);
4017 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);
4018 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4019 qglDepthFunc(GL_LEQUAL);
4020 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4021 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);
4022 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4025 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4028 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4031 GLint allpixels = 0, visiblepixels = 0;
4032 // now we have to check the query result
4033 if (rtlight->corona_queryindex_visiblepixels)
4036 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4037 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4039 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4040 if (visiblepixels < 1 || allpixels < 1)
4042 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4043 cscale *= rtlight->corona_visibility;
4047 // FIXME: these traces should scan all render entities instead of cl.world
4048 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4051 VectorScale(rtlight->color, cscale, color);
4052 if (VectorLength(color) > (1.0f / 256.0f))
4053 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);
4056 void R_DrawCoronas(void)
4064 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4066 if (r_waterstate.renderingscene)
4068 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4069 R_Mesh_Matrix(&identitymatrix);
4071 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4073 // check occlusion of coronas
4074 // use GL_ARB_occlusion_query if available
4075 // otherwise use raytraces
4077 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4080 GL_ColorMask(0,0,0,0);
4081 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4082 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4085 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4086 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4088 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4092 for (lightindex = 0;lightindex < range;lightindex++)
4094 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4097 rtlight = &light->rtlight;
4098 rtlight->corona_visibility = 0;
4099 rtlight->corona_queryindex_visiblepixels = 0;
4100 rtlight->corona_queryindex_allpixels = 0;
4101 if (!(rtlight->flags & flag))
4103 if (rtlight->corona <= 0)
4105 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4107 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4109 for (i = 0;i < r_refdef.scene.numlights;i++)
4111 rtlight = r_refdef.scene.lights[i];
4112 rtlight->corona_visibility = 0;
4113 rtlight->corona_queryindex_visiblepixels = 0;
4114 rtlight->corona_queryindex_allpixels = 0;
4115 if (!(rtlight->flags & flag))
4117 if (rtlight->corona <= 0)
4119 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4122 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4124 // now draw the coronas using the query data for intensity info
4125 for (lightindex = 0;lightindex < range;lightindex++)
4127 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4130 rtlight = &light->rtlight;
4131 if (rtlight->corona_visibility <= 0)
4133 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4135 for (i = 0;i < r_refdef.scene.numlights;i++)
4137 rtlight = r_refdef.scene.lights[i];
4138 if (rtlight->corona_visibility <= 0)
4140 if (gl_flashblend.integer)
4141 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4143 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4149 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4150 typedef struct suffixinfo_s
4153 qboolean flipx, flipy, flipdiagonal;
4156 static suffixinfo_t suffix[3][6] =
4159 {"px", false, false, false},
4160 {"nx", false, false, false},
4161 {"py", false, false, false},
4162 {"ny", false, false, false},
4163 {"pz", false, false, false},
4164 {"nz", false, false, false}
4167 {"posx", false, false, false},
4168 {"negx", false, false, false},
4169 {"posy", false, false, false},
4170 {"negy", false, false, false},
4171 {"posz", false, false, false},
4172 {"negz", false, false, false}
4175 {"rt", true, false, true},
4176 {"lf", false, true, true},
4177 {"ft", true, true, false},
4178 {"bk", false, false, false},
4179 {"up", true, false, true},
4180 {"dn", true, false, true}
4184 static int componentorder[4] = {0, 1, 2, 3};
4186 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4188 int i, j, cubemapsize;
4189 unsigned char *cubemappixels, *image_buffer;
4190 rtexture_t *cubemaptexture;
4192 // must start 0 so the first loadimagepixels has no requested width/height
4194 cubemappixels = NULL;
4195 cubemaptexture = NULL;
4196 // keep trying different suffix groups (posx, px, rt) until one loads
4197 for (j = 0;j < 3 && !cubemappixels;j++)
4199 // load the 6 images in the suffix group
4200 for (i = 0;i < 6;i++)
4202 // generate an image name based on the base and and suffix
4203 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4205 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4207 // an image loaded, make sure width and height are equal
4208 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4210 // if this is the first image to load successfully, allocate the cubemap memory
4211 if (!cubemappixels && image_width >= 1)
4213 cubemapsize = image_width;
4214 // note this clears to black, so unavailable sides are black
4215 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4217 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4219 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);
4222 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4224 Mem_Free(image_buffer);
4228 // if a cubemap loaded, upload it
4231 if (developer_loading.integer)
4232 Con_Printf("loading cubemap \"%s\"\n", basename);
4234 if (!r_shadow_filters_texturepool)
4235 r_shadow_filters_texturepool = R_AllocTexturePool();
4236 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4237 Mem_Free(cubemappixels);
4241 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4242 if (developer_loading.integer)
4244 Con_Printf("(tried tried images ");
4245 for (j = 0;j < 3;j++)
4246 for (i = 0;i < 6;i++)
4247 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4248 Con_Print(" and was unable to find any of them).\n");
4251 return cubemaptexture;
4254 rtexture_t *R_Shadow_Cubemap(const char *basename)
4257 for (i = 0;i < numcubemaps;i++)
4258 if (!strcasecmp(cubemaps[i].basename, basename))
4259 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4260 if (i >= MAX_CUBEMAPS)
4261 return r_texture_whitecube;
4263 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4264 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4265 return cubemaps[i].texture;
4268 void R_Shadow_FreeCubemaps(void)
4271 for (i = 0;i < numcubemaps;i++)
4273 if (developer_loading.integer)
4274 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4275 if (cubemaps[i].texture)
4276 R_FreeTexture(cubemaps[i].texture);
4280 R_FreeTexturePool(&r_shadow_filters_texturepool);
4283 dlight_t *R_Shadow_NewWorldLight(void)
4285 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4288 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)
4291 // validate parameters
4292 if (style < 0 || style >= MAX_LIGHTSTYLES)
4294 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4300 // copy to light properties
4301 VectorCopy(origin, light->origin);
4302 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4303 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4304 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4305 light->color[0] = max(color[0], 0);
4306 light->color[1] = max(color[1], 0);
4307 light->color[2] = max(color[2], 0);
4308 light->radius = max(radius, 0);
4309 light->style = style;
4310 light->shadow = shadowenable;
4311 light->corona = corona;
4312 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4313 light->coronasizescale = coronasizescale;
4314 light->ambientscale = ambientscale;
4315 light->diffusescale = diffusescale;
4316 light->specularscale = specularscale;
4317 light->flags = flags;
4319 // update renderable light data
4320 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4321 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);
4324 void R_Shadow_FreeWorldLight(dlight_t *light)
4326 if (r_shadow_selectedlight == light)
4327 r_shadow_selectedlight = NULL;
4328 R_RTLight_Uncompile(&light->rtlight);
4329 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4332 void R_Shadow_ClearWorldLights(void)
4336 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4337 for (lightindex = 0;lightindex < range;lightindex++)
4339 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4341 R_Shadow_FreeWorldLight(light);
4343 r_shadow_selectedlight = NULL;
4344 R_Shadow_FreeCubemaps();
4347 void R_Shadow_SelectLight(dlight_t *light)
4349 if (r_shadow_selectedlight)
4350 r_shadow_selectedlight->selected = false;
4351 r_shadow_selectedlight = light;
4352 if (r_shadow_selectedlight)
4353 r_shadow_selectedlight->selected = true;
4356 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4358 // this is never batched (there can be only one)
4359 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);
4362 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4369 // this is never batched (due to the ent parameter changing every time)
4370 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4371 const dlight_t *light = (dlight_t *)ent;
4374 VectorScale(light->color, intensity, spritecolor);
4375 if (VectorLength(spritecolor) < 0.1732f)
4376 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4377 if (VectorLength(spritecolor) > 1.0f)
4378 VectorNormalize(spritecolor);
4380 // draw light sprite
4381 if (light->cubemapname[0] && !light->shadow)
4382 pic = r_editlights_sprcubemapnoshadowlight;
4383 else if (light->cubemapname[0])
4384 pic = r_editlights_sprcubemaplight;
4385 else if (!light->shadow)
4386 pic = r_editlights_sprnoshadowlight;
4388 pic = r_editlights_sprlight;
4389 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);
4390 // draw selection sprite if light is selected
4391 if (light->selected)
4392 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);
4393 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4396 void R_Shadow_DrawLightSprites(void)
4400 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4401 for (lightindex = 0;lightindex < range;lightindex++)
4403 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4405 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4407 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4410 void R_Shadow_SelectLightInView(void)
4412 float bestrating, rating, temp[3];
4416 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4419 for (lightindex = 0;lightindex < range;lightindex++)
4421 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4424 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4425 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4428 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4429 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)
4431 bestrating = rating;
4436 R_Shadow_SelectLight(best);
4439 void R_Shadow_LoadWorldLights(void)
4441 int n, a, style, shadow, flags;
4442 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4443 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4444 if (cl.worldmodel == NULL)
4446 Con_Print("No map loaded.\n");
4449 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4450 strlcat (name, ".rtlights", sizeof (name));
4451 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4461 for (;COM_Parse(t, true) && strcmp(
4462 if (COM_Parse(t, true))
4464 if (com_token[0] == '!')
4467 origin[0] = atof(com_token+1);
4470 origin[0] = atof(com_token);
4475 while (*s && *s != '\n' && *s != '\r')
4481 // check for modifier flags
4488 #if _MSC_VER >= 1400
4489 #define sscanf sscanf_s
4491 cubemapname[sizeof(cubemapname)-1] = 0;
4492 #if MAX_QPATH != 128
4493 #error update this code if MAX_QPATH changes
4495 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
4496 #if _MSC_VER >= 1400
4497 , sizeof(cubemapname)
4499 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4502 flags = LIGHTFLAG_REALTIMEMODE;
4510 coronasizescale = 0.25f;
4512 VectorClear(angles);
4515 if (a < 9 || !strcmp(cubemapname, "\"\""))
4517 // remove quotes on cubemapname
4518 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4521 namelen = strlen(cubemapname) - 2;
4522 memmove(cubemapname, cubemapname + 1, namelen);
4523 cubemapname[namelen] = '\0';
4527 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);
4530 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4538 Con_Printf("invalid rtlights file \"%s\"\n", name);
4539 Mem_Free(lightsstring);
4543 void R_Shadow_SaveWorldLights(void)
4547 size_t bufchars, bufmaxchars;
4549 char name[MAX_QPATH];
4550 char line[MAX_INPUTLINE];
4551 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4552 // I hate lines which are 3 times my screen size :( --blub
4555 if (cl.worldmodel == NULL)
4557 Con_Print("No map loaded.\n");
4560 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4561 strlcat (name, ".rtlights", sizeof (name));
4562 bufchars = bufmaxchars = 0;
4564 for (lightindex = 0;lightindex < range;lightindex++)
4566 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4569 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4570 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);
4571 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4572 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]);
4574 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);
4575 if (bufchars + strlen(line) > bufmaxchars)
4577 bufmaxchars = bufchars + strlen(line) + 2048;
4579 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4583 memcpy(buf, oldbuf, bufchars);
4589 memcpy(buf + bufchars, line, strlen(line));
4590 bufchars += strlen(line);
4594 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4599 void R_Shadow_LoadLightsFile(void)
4602 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4603 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4604 if (cl.worldmodel == NULL)
4606 Con_Print("No map loaded.\n");
4609 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4610 strlcat (name, ".lights", sizeof (name));
4611 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4619 while (*s && *s != '\n' && *s != '\r')
4625 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);
4629 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);
4632 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4633 radius = bound(15, radius, 4096);
4634 VectorScale(color, (2.0f / (8388608.0f)), color);
4635 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4643 Con_Printf("invalid lights file \"%s\"\n", name);
4644 Mem_Free(lightsstring);
4648 // tyrlite/hmap2 light types in the delay field
4649 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4651 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4653 int entnum, style, islight, skin, pflags, effects, type, n;
4656 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4657 char key[256], value[MAX_INPUTLINE];
4659 if (cl.worldmodel == NULL)
4661 Con_Print("No map loaded.\n");
4664 // try to load a .ent file first
4665 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4666 strlcat (key, ".ent", sizeof (key));
4667 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4668 // and if that is not found, fall back to the bsp file entity string
4670 data = cl.worldmodel->brush.entities;
4673 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4675 type = LIGHTTYPE_MINUSX;
4676 origin[0] = origin[1] = origin[2] = 0;
4677 originhack[0] = originhack[1] = originhack[2] = 0;
4678 angles[0] = angles[1] = angles[2] = 0;
4679 color[0] = color[1] = color[2] = 1;
4680 light[0] = light[1] = light[2] = 1;light[3] = 300;
4681 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4691 if (!COM_ParseToken_Simple(&data, false, false))
4693 if (com_token[0] == '}')
4694 break; // end of entity
4695 if (com_token[0] == '_')
4696 strlcpy(key, com_token + 1, sizeof(key));
4698 strlcpy(key, com_token, sizeof(key));
4699 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4700 key[strlen(key)-1] = 0;
4701 if (!COM_ParseToken_Simple(&data, false, false))
4703 strlcpy(value, com_token, sizeof(value));
4705 // now that we have the key pair worked out...
4706 if (!strcmp("light", key))
4708 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4712 light[0] = vec[0] * (1.0f / 256.0f);
4713 light[1] = vec[0] * (1.0f / 256.0f);
4714 light[2] = vec[0] * (1.0f / 256.0f);
4720 light[0] = vec[0] * (1.0f / 255.0f);
4721 light[1] = vec[1] * (1.0f / 255.0f);
4722 light[2] = vec[2] * (1.0f / 255.0f);
4726 else if (!strcmp("delay", key))
4728 else if (!strcmp("origin", key))
4729 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4730 else if (!strcmp("angle", key))
4731 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4732 else if (!strcmp("angles", key))
4733 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4734 else if (!strcmp("color", key))
4735 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4736 else if (!strcmp("wait", key))
4737 fadescale = atof(value);
4738 else if (!strcmp("classname", key))
4740 if (!strncmp(value, "light", 5))
4743 if (!strcmp(value, "light_fluoro"))
4748 overridecolor[0] = 1;
4749 overridecolor[1] = 1;
4750 overridecolor[2] = 1;
4752 if (!strcmp(value, "light_fluorospark"))
4757 overridecolor[0] = 1;
4758 overridecolor[1] = 1;
4759 overridecolor[2] = 1;
4761 if (!strcmp(value, "light_globe"))
4766 overridecolor[0] = 1;
4767 overridecolor[1] = 0.8;
4768 overridecolor[2] = 0.4;
4770 if (!strcmp(value, "light_flame_large_yellow"))
4775 overridecolor[0] = 1;
4776 overridecolor[1] = 0.5;
4777 overridecolor[2] = 0.1;
4779 if (!strcmp(value, "light_flame_small_yellow"))
4784 overridecolor[0] = 1;
4785 overridecolor[1] = 0.5;
4786 overridecolor[2] = 0.1;
4788 if (!strcmp(value, "light_torch_small_white"))
4793 overridecolor[0] = 1;
4794 overridecolor[1] = 0.5;
4795 overridecolor[2] = 0.1;
4797 if (!strcmp(value, "light_torch_small_walltorch"))
4802 overridecolor[0] = 1;
4803 overridecolor[1] = 0.5;
4804 overridecolor[2] = 0.1;
4808 else if (!strcmp("style", key))
4809 style = atoi(value);
4810 else if (!strcmp("skin", key))
4811 skin = (int)atof(value);
4812 else if (!strcmp("pflags", key))
4813 pflags = (int)atof(value);
4814 else if (!strcmp("effects", key))
4815 effects = (int)atof(value);
4816 else if (cl.worldmodel->type == mod_brushq3)
4818 if (!strcmp("scale", key))
4819 lightscale = atof(value);
4820 if (!strcmp("fade", key))
4821 fadescale = atof(value);
4826 if (lightscale <= 0)
4830 if (color[0] == color[1] && color[0] == color[2])
4832 color[0] *= overridecolor[0];
4833 color[1] *= overridecolor[1];
4834 color[2] *= overridecolor[2];
4836 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4837 color[0] = color[0] * light[0];
4838 color[1] = color[1] * light[1];
4839 color[2] = color[2] * light[2];
4842 case LIGHTTYPE_MINUSX:
4844 case LIGHTTYPE_RECIPX:
4846 VectorScale(color, (1.0f / 16.0f), color);
4848 case LIGHTTYPE_RECIPXX:
4850 VectorScale(color, (1.0f / 16.0f), color);
4853 case LIGHTTYPE_NONE:
4857 case LIGHTTYPE_MINUSXX:
4860 VectorAdd(origin, originhack, origin);
4862 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);
4865 Mem_Free(entfiledata);
4869 void R_Shadow_SetCursorLocationForView(void)
4872 vec3_t dest, endpos;
4874 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4875 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4876 if (trace.fraction < 1)
4878 dist = trace.fraction * r_editlights_cursordistance.value;
4879 push = r_editlights_cursorpushback.value;
4883 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4884 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4888 VectorClear( endpos );
4890 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4891 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4892 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4895 void R_Shadow_UpdateWorldLightSelection(void)
4897 if (r_editlights.integer)
4899 R_Shadow_SetCursorLocationForView();
4900 R_Shadow_SelectLightInView();
4903 R_Shadow_SelectLight(NULL);
4906 void R_Shadow_EditLights_Clear_f(void)
4908 R_Shadow_ClearWorldLights();
4911 void R_Shadow_EditLights_Reload_f(void)
4915 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
4916 R_Shadow_ClearWorldLights();
4917 R_Shadow_LoadWorldLights();
4918 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4920 R_Shadow_LoadLightsFile();
4921 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
4922 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4926 void R_Shadow_EditLights_Save_f(void)
4930 R_Shadow_SaveWorldLights();
4933 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
4935 R_Shadow_ClearWorldLights();
4936 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
4939 void R_Shadow_EditLights_ImportLightsFile_f(void)
4941 R_Shadow_ClearWorldLights();
4942 R_Shadow_LoadLightsFile();
4945 void R_Shadow_EditLights_Spawn_f(void)
4948 if (!r_editlights.integer)
4950 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4953 if (Cmd_Argc() != 1)
4955 Con_Print("r_editlights_spawn does not take parameters\n");
4958 color[0] = color[1] = color[2] = 1;
4959 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4962 void R_Shadow_EditLights_Edit_f(void)
4964 vec3_t origin, angles, color;
4965 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
4966 int style, shadows, flags, normalmode, realtimemode;
4967 char cubemapname[MAX_INPUTLINE];
4968 if (!r_editlights.integer)
4970 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
4973 if (!r_shadow_selectedlight)
4975 Con_Print("No selected light.\n");
4978 VectorCopy(r_shadow_selectedlight->origin, origin);
4979 VectorCopy(r_shadow_selectedlight->angles, angles);
4980 VectorCopy(r_shadow_selectedlight->color, color);
4981 radius = r_shadow_selectedlight->radius;
4982 style = r_shadow_selectedlight->style;
4983 if (r_shadow_selectedlight->cubemapname)
4984 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
4987 shadows = r_shadow_selectedlight->shadow;
4988 corona = r_shadow_selectedlight->corona;
4989 coronasizescale = r_shadow_selectedlight->coronasizescale;
4990 ambientscale = r_shadow_selectedlight->ambientscale;
4991 diffusescale = r_shadow_selectedlight->diffusescale;
4992 specularscale = r_shadow_selectedlight->specularscale;
4993 flags = r_shadow_selectedlight->flags;
4994 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
4995 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
4996 if (!strcmp(Cmd_Argv(1), "origin"))
4998 if (Cmd_Argc() != 5)
5000 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5003 origin[0] = atof(Cmd_Argv(2));
5004 origin[1] = atof(Cmd_Argv(3));
5005 origin[2] = atof(Cmd_Argv(4));
5007 else if (!strcmp(Cmd_Argv(1), "originx"))
5009 if (Cmd_Argc() != 3)
5011 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5014 origin[0] = atof(Cmd_Argv(2));
5016 else if (!strcmp(Cmd_Argv(1), "originy"))
5018 if (Cmd_Argc() != 3)
5020 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5023 origin[1] = atof(Cmd_Argv(2));
5025 else if (!strcmp(Cmd_Argv(1), "originz"))
5027 if (Cmd_Argc() != 3)
5029 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5032 origin[2] = atof(Cmd_Argv(2));
5034 else if (!strcmp(Cmd_Argv(1), "move"))
5036 if (Cmd_Argc() != 5)
5038 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5041 origin[0] += atof(Cmd_Argv(2));
5042 origin[1] += atof(Cmd_Argv(3));
5043 origin[2] += atof(Cmd_Argv(4));
5045 else if (!strcmp(Cmd_Argv(1), "movex"))
5047 if (Cmd_Argc() != 3)
5049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5052 origin[0] += atof(Cmd_Argv(2));
5054 else if (!strcmp(Cmd_Argv(1), "movey"))
5056 if (Cmd_Argc() != 3)
5058 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5061 origin[1] += atof(Cmd_Argv(2));
5063 else if (!strcmp(Cmd_Argv(1), "movez"))
5065 if (Cmd_Argc() != 3)
5067 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5070 origin[2] += atof(Cmd_Argv(2));
5072 else if (!strcmp(Cmd_Argv(1), "angles"))
5074 if (Cmd_Argc() != 5)
5076 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5079 angles[0] = atof(Cmd_Argv(2));
5080 angles[1] = atof(Cmd_Argv(3));
5081 angles[2] = atof(Cmd_Argv(4));
5083 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5085 if (Cmd_Argc() != 3)
5087 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5090 angles[0] = atof(Cmd_Argv(2));
5092 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5094 if (Cmd_Argc() != 3)
5096 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5099 angles[1] = atof(Cmd_Argv(2));
5101 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5103 if (Cmd_Argc() != 3)
5105 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5108 angles[2] = atof(Cmd_Argv(2));
5110 else if (!strcmp(Cmd_Argv(1), "color"))
5112 if (Cmd_Argc() != 5)
5114 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5117 color[0] = atof(Cmd_Argv(2));
5118 color[1] = atof(Cmd_Argv(3));
5119 color[2] = atof(Cmd_Argv(4));
5121 else if (!strcmp(Cmd_Argv(1), "radius"))
5123 if (Cmd_Argc() != 3)
5125 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5128 radius = atof(Cmd_Argv(2));
5130 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5132 if (Cmd_Argc() == 3)
5134 double scale = atof(Cmd_Argv(2));
5141 if (Cmd_Argc() != 5)
5143 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5146 color[0] *= atof(Cmd_Argv(2));
5147 color[1] *= atof(Cmd_Argv(3));
5148 color[2] *= atof(Cmd_Argv(4));
5151 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5153 if (Cmd_Argc() != 3)
5155 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5158 radius *= atof(Cmd_Argv(2));
5160 else if (!strcmp(Cmd_Argv(1), "style"))
5162 if (Cmd_Argc() != 3)
5164 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5167 style = atoi(Cmd_Argv(2));
5169 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5173 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5176 if (Cmd_Argc() == 3)
5177 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5181 else if (!strcmp(Cmd_Argv(1), "shadows"))
5183 if (Cmd_Argc() != 3)
5185 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5188 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5190 else if (!strcmp(Cmd_Argv(1), "corona"))
5192 if (Cmd_Argc() != 3)
5194 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5197 corona = atof(Cmd_Argv(2));
5199 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5201 if (Cmd_Argc() != 3)
5203 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5206 coronasizescale = atof(Cmd_Argv(2));
5208 else if (!strcmp(Cmd_Argv(1), "ambient"))
5210 if (Cmd_Argc() != 3)
5212 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5215 ambientscale = atof(Cmd_Argv(2));
5217 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5219 if (Cmd_Argc() != 3)
5221 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5224 diffusescale = atof(Cmd_Argv(2));
5226 else if (!strcmp(Cmd_Argv(1), "specular"))
5228 if (Cmd_Argc() != 3)
5230 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5233 specularscale = atof(Cmd_Argv(2));
5235 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5237 if (Cmd_Argc() != 3)
5239 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5242 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5244 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5246 if (Cmd_Argc() != 3)
5248 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5251 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5255 Con_Print("usage: r_editlights_edit [property] [value]\n");
5256 Con_Print("Selected light's properties:\n");
5257 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5258 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5259 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5260 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5261 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5262 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5263 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5264 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5265 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5266 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5267 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5268 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5269 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5270 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5273 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5274 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5277 void R_Shadow_EditLights_EditAll_f(void)
5283 if (!r_editlights.integer)
5285 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5289 // EditLights doesn't seem to have a "remove" command or something so:
5290 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5291 for (lightindex = 0;lightindex < range;lightindex++)
5293 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5296 R_Shadow_SelectLight(light);
5297 R_Shadow_EditLights_Edit_f();
5301 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5303 int lightnumber, lightcount;
5304 size_t lightindex, range;
5308 if (!r_editlights.integer)
5310 x = vid_conwidth.value - 240;
5312 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5315 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5316 for (lightindex = 0;lightindex < range;lightindex++)
5318 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5321 if (light == r_shadow_selectedlight)
5322 lightnumber = lightindex;
5325 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;
5326 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;
5328 if (r_shadow_selectedlight == NULL)
5330 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;
5331 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;
5332 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;
5333 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;
5334 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;
5335 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;
5336 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;
5337 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;
5338 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;
5339 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;
5340 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;
5341 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;
5342 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;
5343 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;
5344 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;
5347 void R_Shadow_EditLights_ToggleShadow_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_ToggleCorona_f(void)
5364 if (!r_editlights.integer)
5366 Con_Print("Cannot spawn 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_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);
5377 void R_Shadow_EditLights_Remove_f(void)
5379 if (!r_editlights.integer)
5381 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5384 if (!r_shadow_selectedlight)
5386 Con_Print("No selected light.\n");
5389 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5390 r_shadow_selectedlight = NULL;
5393 void R_Shadow_EditLights_Help_f(void)
5396 "Documentation on r_editlights system:\n"
5398 "r_editlights : enable/disable editing mode\n"
5399 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5400 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5401 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5402 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5403 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5405 "r_editlights_help : this help\n"
5406 "r_editlights_clear : remove all lights\n"
5407 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5408 "r_editlights_save : save to .rtlights file\n"
5409 "r_editlights_spawn : create a light with default settings\n"
5410 "r_editlights_edit command : edit selected light - more documentation below\n"
5411 "r_editlights_remove : remove selected light\n"
5412 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5413 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5414 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5416 "origin x y z : set light location\n"
5417 "originx x: set x component of light location\n"
5418 "originy y: set y component of light location\n"
5419 "originz z: set z component of light location\n"
5420 "move x y z : adjust light location\n"
5421 "movex x: adjust x component of light location\n"
5422 "movey y: adjust y component of light location\n"
5423 "movez z: adjust z component of light location\n"
5424 "angles x y z : set light angles\n"
5425 "anglesx x: set x component of light angles\n"
5426 "anglesy y: set y component of light angles\n"
5427 "anglesz z: set z component of light angles\n"
5428 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5429 "radius radius : set radius (size) of light\n"
5430 "colorscale grey : multiply color of light (1 does nothing)\n"
5431 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5432 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5433 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5434 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5435 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5436 "shadows 1/0 : turn on/off shadows\n"
5437 "corona n : set corona intensity\n"
5438 "coronasize n : set corona size (0-1)\n"
5439 "ambient n : set ambient intensity (0-1)\n"
5440 "diffuse n : set diffuse intensity (0-1)\n"
5441 "specular n : set specular intensity (0-1)\n"
5442 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5443 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5444 "<nothing> : print light properties to console\n"
5448 void R_Shadow_EditLights_CopyInfo_f(void)
5450 if (!r_editlights.integer)
5452 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5455 if (!r_shadow_selectedlight)
5457 Con_Print("No selected light.\n");
5460 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5461 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5462 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5463 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5464 if (r_shadow_selectedlight->cubemapname)
5465 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5467 r_shadow_bufferlight.cubemapname[0] = 0;
5468 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5469 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5470 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5471 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5472 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5473 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5474 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5477 void R_Shadow_EditLights_PasteInfo_f(void)
5479 if (!r_editlights.integer)
5481 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5484 if (!r_shadow_selectedlight)
5486 Con_Print("No selected light.\n");
5489 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);
5492 void R_Shadow_EditLights_Init(void)
5494 Cvar_RegisterVariable(&r_editlights);
5495 Cvar_RegisterVariable(&r_editlights_cursordistance);
5496 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5497 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5498 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5499 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5500 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5501 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5502 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)");
5503 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5504 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5505 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5506 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)");
5507 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5508 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5509 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5510 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5511 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5512 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5513 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)");
5519 =============================================================================
5523 =============================================================================
5526 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5528 VectorClear(diffusecolor);
5529 VectorClear(diffusenormal);
5531 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5533 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5534 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5537 VectorSet(ambientcolor, 1, 1, 1);
5544 for (i = 0;i < r_refdef.scene.numlights;i++)
5546 light = r_refdef.scene.lights[i];
5547 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5548 f = 1 - VectorLength2(v);
5549 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5550 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);