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_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmaprectangletexture;
248 rtexture_t *r_shadow_shadowmap2dtexture;
249 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 // lights are reloaded when this changes
255 char r_shadow_mapname[MAX_QPATH];
257 // used only for light filters (cubemaps)
258 rtexturepool_t *r_shadow_filters_texturepool;
260 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"};
261 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"};
262 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
263 cvar_t r_shadow_dot3 = {CVAR_SAVE, "r_shadow_dot3", "0", "enables use of (slow) per pixel lighting on GL1.3 hardware"};
264 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
265 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)"};
266 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"};
267 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
268 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
269 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
270 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
271 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
272 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
274 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
275 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
276 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
277 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)"};
278 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
279 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
280 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
281 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
282 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)"};
283 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"};
284 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
285 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
286 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"};
287 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
288 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
289 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)"};
290 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"};
291 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
292 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
293 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
294 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
295 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
296 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
298 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
299 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
300 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
301 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
302 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
303 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
304 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
305 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
306 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
307 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)"};
308 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)"};
309 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
310 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"};
311 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
312 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
313 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
314 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
315 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
316 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
317 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
318 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
319 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
320 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
322 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
323 #define ATTENTABLESIZE 256
324 // 1D gradient, 2D circle and 3D sphere attenuation textures
325 #define ATTEN1DSIZE 32
326 #define ATTEN2DSIZE 64
327 #define ATTEN3DSIZE 32
329 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
330 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
331 static float r_shadow_attentable[ATTENTABLESIZE+1];
333 rtlight_t *r_shadow_compilingrtlight;
334 static memexpandablearray_t r_shadow_worldlightsarray;
335 dlight_t *r_shadow_selectedlight;
336 dlight_t r_shadow_bufferlight;
337 vec3_t r_editlights_cursorlocation;
339 extern int con_vislines;
341 typedef struct cubemapinfo_s
348 static int numcubemaps;
349 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 #define EDLIGHTSPRSIZE 8
362 skinframe_t *r_editlights_sprcursor;
363 skinframe_t *r_editlights_sprlight;
364 skinframe_t *r_editlights_sprnoshadowlight;
365 skinframe_t *r_editlights_sprcubemaplight;
366 skinframe_t *r_editlights_sprcubemapnoshadowlight;
367 skinframe_t *r_editlights_sprselection;
368 extern cvar_t gl_max_size;
370 void R_Shadow_SetShadowMode(void)
372 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4);
373 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
374 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
375 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
376 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 if(r_shadow_shadowmapping.integer && r_glsl.integer && vid.support.arb_fragment_shader && vid.support.ext_framebuffer_object)
385 if(r_shadow_shadowmapfilterquality < 0)
387 if(strstr(gl_vendor, "NVIDIA"))
389 r_shadow_shadowmapsampler = vid.support.arb_shadow;
390 r_shadow_shadowmappcf = 1;
392 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
393 r_shadow_shadowmappcf = 1;
394 else if(strstr(gl_vendor, "ATI"))
395 r_shadow_shadowmappcf = 1;
397 r_shadow_shadowmapsampler = vid.support.arb_shadow;
401 switch (r_shadow_shadowmapfilterquality)
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 r_shadow_shadowmappcf = 1;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 2;
418 switch (r_shadow_shadowmaptexturetype)
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
424 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
427 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
430 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
432 else if(vid.support.arb_texture_rectangle)
433 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
435 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
441 void R_Shadow_FreeShadowMaps(void)
445 R_Shadow_SetShadowMode();
447 if (r_shadow_fborectangle)
448 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
449 r_shadow_fborectangle = 0;
453 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
456 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
457 if (r_shadow_fbocubeside[i])
458 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);
459 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
462 if (r_shadow_shadowmaprectangletexture)
463 R_FreeTexture(r_shadow_shadowmaprectangletexture);
464 r_shadow_shadowmaprectangletexture = NULL;
466 if (r_shadow_shadowmap2dtexture)
467 R_FreeTexture(r_shadow_shadowmap2dtexture);
468 r_shadow_shadowmap2dtexture = NULL;
470 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
471 if (r_shadow_shadowmapcubetexture[i])
472 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
473 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
475 if (r_shadow_shadowmapvsdcttexture)
476 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
477 r_shadow_shadowmapvsdcttexture = NULL;
482 void r_shadow_start(void)
484 // allocate vertex processing arrays
486 r_shadow_attenuationgradienttexture = NULL;
487 r_shadow_attenuation2dtexture = NULL;
488 r_shadow_attenuation3dtexture = NULL;
489 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
490 r_shadow_shadowmaprectangletexture = NULL;
491 r_shadow_shadowmap2dtexture = NULL;
492 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
493 r_shadow_shadowmapvsdcttexture = NULL;
494 r_shadow_shadowmapmaxsize = 0;
495 r_shadow_shadowmapsize = 0;
496 r_shadow_shadowmaplod = 0;
497 r_shadow_shadowmapfilterquality = -1;
498 r_shadow_shadowmaptexturetype = -1;
499 r_shadow_shadowmapdepthbits = 0;
500 r_shadow_shadowmapvsdct = false;
501 r_shadow_shadowmapsampler = false;
502 r_shadow_shadowmappcf = 0;
503 r_shadow_fborectangle = 0;
505 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
507 R_Shadow_FreeShadowMaps();
509 r_shadow_texturepool = NULL;
510 r_shadow_filters_texturepool = NULL;
511 R_Shadow_ValidateCvars();
512 R_Shadow_MakeTextures();
513 maxshadowtriangles = 0;
514 shadowelements = NULL;
515 maxshadowvertices = 0;
516 shadowvertex3f = NULL;
524 shadowmarklist = NULL;
529 shadowsideslist = NULL;
530 r_shadow_buffer_numleafpvsbytes = 0;
531 r_shadow_buffer_visitingleafpvs = NULL;
532 r_shadow_buffer_leafpvs = NULL;
533 r_shadow_buffer_leaflist = NULL;
534 r_shadow_buffer_numsurfacepvsbytes = 0;
535 r_shadow_buffer_surfacepvs = NULL;
536 r_shadow_buffer_surfacelist = NULL;
537 r_shadow_buffer_surfacesides = NULL;
538 r_shadow_buffer_numshadowtrispvsbytes = 0;
539 r_shadow_buffer_shadowtrispvs = NULL;
540 r_shadow_buffer_numlighttrispvsbytes = 0;
541 r_shadow_buffer_lighttrispvs = NULL;
544 void r_shadow_shutdown(void)
547 R_Shadow_UncompileWorldLights();
549 R_Shadow_FreeShadowMaps();
553 r_shadow_attenuationgradienttexture = NULL;
554 r_shadow_attenuation2dtexture = NULL;
555 r_shadow_attenuation3dtexture = NULL;
556 R_FreeTexturePool(&r_shadow_texturepool);
557 R_FreeTexturePool(&r_shadow_filters_texturepool);
558 maxshadowtriangles = 0;
560 Mem_Free(shadowelements);
561 shadowelements = NULL;
563 Mem_Free(shadowvertex3f);
564 shadowvertex3f = NULL;
567 Mem_Free(vertexupdate);
570 Mem_Free(vertexremap);
576 Mem_Free(shadowmark);
579 Mem_Free(shadowmarklist);
580 shadowmarklist = NULL;
585 Mem_Free(shadowsides);
588 Mem_Free(shadowsideslist);
589 shadowsideslist = NULL;
590 r_shadow_buffer_numleafpvsbytes = 0;
591 if (r_shadow_buffer_visitingleafpvs)
592 Mem_Free(r_shadow_buffer_visitingleafpvs);
593 r_shadow_buffer_visitingleafpvs = NULL;
594 if (r_shadow_buffer_leafpvs)
595 Mem_Free(r_shadow_buffer_leafpvs);
596 r_shadow_buffer_leafpvs = NULL;
597 if (r_shadow_buffer_leaflist)
598 Mem_Free(r_shadow_buffer_leaflist);
599 r_shadow_buffer_leaflist = NULL;
600 r_shadow_buffer_numsurfacepvsbytes = 0;
601 if (r_shadow_buffer_surfacepvs)
602 Mem_Free(r_shadow_buffer_surfacepvs);
603 r_shadow_buffer_surfacepvs = NULL;
604 if (r_shadow_buffer_surfacelist)
605 Mem_Free(r_shadow_buffer_surfacelist);
606 r_shadow_buffer_surfacelist = NULL;
607 if (r_shadow_buffer_surfacesides)
608 Mem_Free(r_shadow_buffer_surfacesides);
609 r_shadow_buffer_surfacesides = NULL;
610 r_shadow_buffer_numshadowtrispvsbytes = 0;
611 if (r_shadow_buffer_shadowtrispvs)
612 Mem_Free(r_shadow_buffer_shadowtrispvs);
613 r_shadow_buffer_numlighttrispvsbytes = 0;
614 if (r_shadow_buffer_lighttrispvs)
615 Mem_Free(r_shadow_buffer_lighttrispvs);
618 void r_shadow_newmap(void)
620 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
621 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
622 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
623 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
624 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
625 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
626 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
627 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
628 R_Shadow_EditLights_Reload_f();
631 void R_Shadow_Help_f(void)
634 "Documentation on r_shadow system:\n"
636 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
637 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
638 "r_shadow_debuglight : render only this light number (-1 = all)\n"
639 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
640 "r_shadow_gloss2intensity : brightness of forced gloss\n"
641 "r_shadow_glossintensity : brightness of textured gloss\n"
642 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
643 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
644 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
645 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
646 "r_shadow_portallight : use portal visibility for static light precomputation\n"
647 "r_shadow_projectdistance : shadow volume projection distance\n"
648 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
649 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
650 "r_shadow_realtime_world : use high quality world lighting mode\n"
651 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
652 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
653 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
654 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
655 "r_shadow_scissor : use scissor optimization\n"
656 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
657 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
658 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
659 "r_showlighting : useful for performance testing; bright = slow!\n"
660 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
662 "r_shadow_help : this help\n"
666 void R_Shadow_Init(void)
668 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
669 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
670 Cvar_RegisterVariable(&r_shadow_dot3);
671 Cvar_RegisterVariable(&r_shadow_usenormalmap);
672 Cvar_RegisterVariable(&r_shadow_debuglight);
673 Cvar_RegisterVariable(&r_shadow_gloss);
674 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
675 Cvar_RegisterVariable(&r_shadow_glossintensity);
676 Cvar_RegisterVariable(&r_shadow_glossexponent);
677 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
678 Cvar_RegisterVariable(&r_shadow_glossexact);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
681 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
682 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
683 Cvar_RegisterVariable(&r_shadow_portallight);
684 Cvar_RegisterVariable(&r_shadow_projectdistance);
685 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
690 Cvar_RegisterVariable(&r_shadow_realtime_world);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
697 Cvar_RegisterVariable(&r_shadow_scissor);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
706 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
707 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
713 Cvar_RegisterVariable(&r_shadow_culltriangles);
714 Cvar_RegisterVariable(&r_shadow_polygonfactor);
715 Cvar_RegisterVariable(&r_shadow_polygonoffset);
716 Cvar_RegisterVariable(&r_shadow_texture3d);
717 Cvar_RegisterVariable(&r_coronas);
718 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
719 Cvar_RegisterVariable(&r_coronas_occlusionquery);
720 Cvar_RegisterVariable(&gl_flashblend);
721 Cvar_RegisterVariable(&gl_ext_separatestencil);
722 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
723 if (gamemode == GAME_TENEBRAE)
725 Cvar_SetValue("r_shadow_gloss", 2);
726 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
728 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
729 R_Shadow_EditLights_Init();
730 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
731 maxshadowtriangles = 0;
732 shadowelements = NULL;
733 maxshadowvertices = 0;
734 shadowvertex3f = NULL;
742 shadowmarklist = NULL;
747 shadowsideslist = NULL;
748 r_shadow_buffer_numleafpvsbytes = 0;
749 r_shadow_buffer_visitingleafpvs = NULL;
750 r_shadow_buffer_leafpvs = NULL;
751 r_shadow_buffer_leaflist = NULL;
752 r_shadow_buffer_numsurfacepvsbytes = 0;
753 r_shadow_buffer_surfacepvs = NULL;
754 r_shadow_buffer_surfacelist = NULL;
755 r_shadow_buffer_surfacesides = NULL;
756 r_shadow_buffer_shadowtrispvs = NULL;
757 r_shadow_buffer_lighttrispvs = NULL;
758 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
761 matrix4x4_t matrix_attenuationxyz =
764 {0.5, 0.0, 0.0, 0.5},
765 {0.0, 0.5, 0.0, 0.5},
766 {0.0, 0.0, 0.5, 0.5},
771 matrix4x4_t matrix_attenuationz =
774 {0.0, 0.0, 0.5, 0.5},
775 {0.0, 0.0, 0.0, 0.5},
776 {0.0, 0.0, 0.0, 0.5},
781 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
783 numvertices = ((numvertices + 255) & ~255) * vertscale;
784 numtriangles = ((numtriangles + 255) & ~255) * triscale;
785 // make sure shadowelements is big enough for this volume
786 if (maxshadowtriangles < numtriangles)
788 maxshadowtriangles = numtriangles;
790 Mem_Free(shadowelements);
791 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
793 // make sure shadowvertex3f is big enough for this volume
794 if (maxshadowvertices < numvertices)
796 maxshadowvertices = numvertices;
798 Mem_Free(shadowvertex3f);
799 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
803 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
805 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
806 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
807 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
808 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
809 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
811 if (r_shadow_buffer_visitingleafpvs)
812 Mem_Free(r_shadow_buffer_visitingleafpvs);
813 if (r_shadow_buffer_leafpvs)
814 Mem_Free(r_shadow_buffer_leafpvs);
815 if (r_shadow_buffer_leaflist)
816 Mem_Free(r_shadow_buffer_leaflist);
817 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
818 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
819 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
820 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
822 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
824 if (r_shadow_buffer_surfacepvs)
825 Mem_Free(r_shadow_buffer_surfacepvs);
826 if (r_shadow_buffer_surfacelist)
827 Mem_Free(r_shadow_buffer_surfacelist);
828 if (r_shadow_buffer_surfacesides)
829 Mem_Free(r_shadow_buffer_surfacesides);
830 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
831 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
832 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
833 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
835 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
837 if (r_shadow_buffer_shadowtrispvs)
838 Mem_Free(r_shadow_buffer_shadowtrispvs);
839 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
840 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
842 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
844 if (r_shadow_buffer_lighttrispvs)
845 Mem_Free(r_shadow_buffer_lighttrispvs);
846 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
847 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
851 void R_Shadow_PrepareShadowMark(int numtris)
853 // make sure shadowmark is big enough for this volume
854 if (maxshadowmark < numtris)
856 maxshadowmark = numtris;
858 Mem_Free(shadowmark);
860 Mem_Free(shadowmarklist);
861 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
862 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
866 // if shadowmarkcount wrapped we clear the array and adjust accordingly
867 if (shadowmarkcount == 0)
870 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
875 void R_Shadow_PrepareShadowSides(int numtris)
877 if (maxshadowsides < numtris)
879 maxshadowsides = numtris;
881 Mem_Free(shadowsides);
883 Mem_Free(shadowsideslist);
884 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
885 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
890 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)
893 int outtriangles = 0, outvertices = 0;
896 float ratio, direction[3], projectvector[3];
898 if (projectdirection)
899 VectorScale(projectdirection, projectdistance, projectvector);
901 VectorClear(projectvector);
903 // create the vertices
904 if (projectdirection)
906 for (i = 0;i < numshadowmarktris;i++)
908 element = inelement3i + shadowmarktris[i] * 3;
909 for (j = 0;j < 3;j++)
911 if (vertexupdate[element[j]] != vertexupdatenum)
913 vertexupdate[element[j]] = vertexupdatenum;
914 vertexremap[element[j]] = outvertices;
915 vertex = invertex3f + element[j] * 3;
916 // project one copy of the vertex according to projectvector
917 VectorCopy(vertex, outvertex3f);
918 VectorAdd(vertex, projectvector, (outvertex3f + 3));
927 for (i = 0;i < numshadowmarktris;i++)
929 element = inelement3i + shadowmarktris[i] * 3;
930 for (j = 0;j < 3;j++)
932 if (vertexupdate[element[j]] != vertexupdatenum)
934 vertexupdate[element[j]] = vertexupdatenum;
935 vertexremap[element[j]] = outvertices;
936 vertex = invertex3f + element[j] * 3;
937 // project one copy of the vertex to the sphere radius of the light
938 // (FIXME: would projecting it to the light box be better?)
939 VectorSubtract(vertex, projectorigin, direction);
940 ratio = projectdistance / VectorLength(direction);
941 VectorCopy(vertex, outvertex3f);
942 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
950 if (r_shadow_frontsidecasting.integer)
952 for (i = 0;i < numshadowmarktris;i++)
954 int remappedelement[3];
956 const int *neighbortriangle;
958 markindex = shadowmarktris[i] * 3;
959 element = inelement3i + markindex;
960 neighbortriangle = inneighbor3i + markindex;
961 // output the front and back triangles
962 outelement3i[0] = vertexremap[element[0]];
963 outelement3i[1] = vertexremap[element[1]];
964 outelement3i[2] = vertexremap[element[2]];
965 outelement3i[3] = vertexremap[element[2]] + 1;
966 outelement3i[4] = vertexremap[element[1]] + 1;
967 outelement3i[5] = vertexremap[element[0]] + 1;
971 // output the sides (facing outward from this triangle)
972 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
974 remappedelement[0] = vertexremap[element[0]];
975 remappedelement[1] = vertexremap[element[1]];
976 outelement3i[0] = remappedelement[1];
977 outelement3i[1] = remappedelement[0];
978 outelement3i[2] = remappedelement[0] + 1;
979 outelement3i[3] = remappedelement[1];
980 outelement3i[4] = remappedelement[0] + 1;
981 outelement3i[5] = remappedelement[1] + 1;
986 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
988 remappedelement[1] = vertexremap[element[1]];
989 remappedelement[2] = vertexremap[element[2]];
990 outelement3i[0] = remappedelement[2];
991 outelement3i[1] = remappedelement[1];
992 outelement3i[2] = remappedelement[1] + 1;
993 outelement3i[3] = remappedelement[2];
994 outelement3i[4] = remappedelement[1] + 1;
995 outelement3i[5] = remappedelement[2] + 1;
1000 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1002 remappedelement[0] = vertexremap[element[0]];
1003 remappedelement[2] = vertexremap[element[2]];
1004 outelement3i[0] = remappedelement[0];
1005 outelement3i[1] = remappedelement[2];
1006 outelement3i[2] = remappedelement[2] + 1;
1007 outelement3i[3] = remappedelement[0];
1008 outelement3i[4] = remappedelement[2] + 1;
1009 outelement3i[5] = remappedelement[0] + 1;
1018 for (i = 0;i < numshadowmarktris;i++)
1020 int remappedelement[3];
1022 const int *neighbortriangle;
1024 markindex = shadowmarktris[i] * 3;
1025 element = inelement3i + markindex;
1026 neighbortriangle = inneighbor3i + markindex;
1027 // output the front and back triangles
1028 outelement3i[0] = vertexremap[element[2]];
1029 outelement3i[1] = vertexremap[element[1]];
1030 outelement3i[2] = vertexremap[element[0]];
1031 outelement3i[3] = vertexremap[element[0]] + 1;
1032 outelement3i[4] = vertexremap[element[1]] + 1;
1033 outelement3i[5] = vertexremap[element[2]] + 1;
1037 // output the sides (facing outward from this triangle)
1038 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1040 remappedelement[0] = vertexremap[element[0]];
1041 remappedelement[1] = vertexremap[element[1]];
1042 outelement3i[0] = remappedelement[0];
1043 outelement3i[1] = remappedelement[1];
1044 outelement3i[2] = remappedelement[1] + 1;
1045 outelement3i[3] = remappedelement[0];
1046 outelement3i[4] = remappedelement[1] + 1;
1047 outelement3i[5] = remappedelement[0] + 1;
1052 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1054 remappedelement[1] = vertexremap[element[1]];
1055 remappedelement[2] = vertexremap[element[2]];
1056 outelement3i[0] = remappedelement[1];
1057 outelement3i[1] = remappedelement[2];
1058 outelement3i[2] = remappedelement[2] + 1;
1059 outelement3i[3] = remappedelement[1];
1060 outelement3i[4] = remappedelement[2] + 1;
1061 outelement3i[5] = remappedelement[1] + 1;
1066 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1068 remappedelement[0] = vertexremap[element[0]];
1069 remappedelement[2] = vertexremap[element[2]];
1070 outelement3i[0] = remappedelement[2];
1071 outelement3i[1] = remappedelement[0];
1072 outelement3i[2] = remappedelement[0] + 1;
1073 outelement3i[3] = remappedelement[2];
1074 outelement3i[4] = remappedelement[0] + 1;
1075 outelement3i[5] = remappedelement[2] + 1;
1083 *outnumvertices = outvertices;
1084 return outtriangles;
1087 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)
1090 int outtriangles = 0, outvertices = 0;
1092 const float *vertex;
1093 float ratio, direction[3], projectvector[3];
1096 if (projectdirection)
1097 VectorScale(projectdirection, projectdistance, projectvector);
1099 VectorClear(projectvector);
1101 for (i = 0;i < numshadowmarktris;i++)
1103 int remappedelement[3];
1105 const int *neighbortriangle;
1107 markindex = shadowmarktris[i] * 3;
1108 neighbortriangle = inneighbor3i + markindex;
1109 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1110 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1111 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1112 if (side[0] + side[1] + side[2] == 0)
1116 element = inelement3i + markindex;
1118 // create the vertices
1119 for (j = 0;j < 3;j++)
1121 if (side[j] + side[j+1] == 0)
1124 if (vertexupdate[k] != vertexupdatenum)
1126 vertexupdate[k] = vertexupdatenum;
1127 vertexremap[k] = outvertices;
1128 vertex = invertex3f + k * 3;
1129 VectorCopy(vertex, outvertex3f);
1130 if (projectdirection)
1132 // project one copy of the vertex according to projectvector
1133 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1137 // project one copy of the vertex to the sphere radius of the light
1138 // (FIXME: would projecting it to the light box be better?)
1139 VectorSubtract(vertex, projectorigin, direction);
1140 ratio = projectdistance / VectorLength(direction);
1141 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1148 // output the sides (facing outward from this triangle)
1151 remappedelement[0] = vertexremap[element[0]];
1152 remappedelement[1] = vertexremap[element[1]];
1153 outelement3i[0] = remappedelement[1];
1154 outelement3i[1] = remappedelement[0];
1155 outelement3i[2] = remappedelement[0] + 1;
1156 outelement3i[3] = remappedelement[1];
1157 outelement3i[4] = remappedelement[0] + 1;
1158 outelement3i[5] = remappedelement[1] + 1;
1165 remappedelement[1] = vertexremap[element[1]];
1166 remappedelement[2] = vertexremap[element[2]];
1167 outelement3i[0] = remappedelement[2];
1168 outelement3i[1] = remappedelement[1];
1169 outelement3i[2] = remappedelement[1] + 1;
1170 outelement3i[3] = remappedelement[2];
1171 outelement3i[4] = remappedelement[1] + 1;
1172 outelement3i[5] = remappedelement[2] + 1;
1179 remappedelement[0] = vertexremap[element[0]];
1180 remappedelement[2] = vertexremap[element[2]];
1181 outelement3i[0] = remappedelement[0];
1182 outelement3i[1] = remappedelement[2];
1183 outelement3i[2] = remappedelement[2] + 1;
1184 outelement3i[3] = remappedelement[0];
1185 outelement3i[4] = remappedelement[2] + 1;
1186 outelement3i[5] = remappedelement[0] + 1;
1193 *outnumvertices = outvertices;
1194 return outtriangles;
1197 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)
1203 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1205 tend = firsttriangle + numtris;
1206 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1208 // surface box entirely inside light box, no box cull
1209 if (projectdirection)
1211 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1213 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1214 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1215 shadowmarklist[numshadowmark++] = t;
1220 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1221 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1222 shadowmarklist[numshadowmark++] = t;
1227 // surface box not entirely inside light box, cull each triangle
1228 if (projectdirection)
1230 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1232 v[0] = invertex3f + e[0] * 3;
1233 v[1] = invertex3f + e[1] * 3;
1234 v[2] = invertex3f + e[2] * 3;
1235 TriangleNormal(v[0], v[1], v[2], normal);
1236 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1237 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1238 shadowmarklist[numshadowmark++] = t;
1243 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1245 v[0] = invertex3f + e[0] * 3;
1246 v[1] = invertex3f + e[1] * 3;
1247 v[2] = invertex3f + e[2] * 3;
1248 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1249 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1250 shadowmarklist[numshadowmark++] = t;
1256 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1261 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1263 // check if the shadow volume intersects the near plane
1265 // a ray between the eye and light origin may intersect the caster,
1266 // indicating that the shadow may touch the eye location, however we must
1267 // test the near plane (a polygon), not merely the eye location, so it is
1268 // easiest to enlarge the caster bounding shape slightly for this.
1274 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)
1276 int i, tris, outverts;
1277 if (projectdistance < 0.1)
1279 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1282 if (!numverts || !nummarktris)
1284 // make sure shadowelements is big enough for this volume
1285 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1286 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1288 if (maxvertexupdate < numverts)
1290 maxvertexupdate = numverts;
1292 Mem_Free(vertexupdate);
1294 Mem_Free(vertexremap);
1295 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1296 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1297 vertexupdatenum = 0;
1300 if (vertexupdatenum == 0)
1302 vertexupdatenum = 1;
1303 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1304 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1307 for (i = 0;i < nummarktris;i++)
1308 shadowmark[marktris[i]] = shadowmarkcount;
1310 if (r_shadow_compilingrtlight)
1312 // if we're compiling an rtlight, capture the mesh
1313 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1314 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1315 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1316 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1320 // decide which type of shadow to generate and set stencil mode
1321 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1322 // generate the sides or a solid volume, depending on type
1323 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1324 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1327 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1328 r_refdef.stats.lights_shadowtriangles += tris;
1330 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1331 GL_LockArrays(0, outverts);
1332 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1334 // increment stencil if frontface is infront of depthbuffer
1335 GL_CullFace(r_refdef.view.cullface_front);
1336 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1337 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1338 // decrement stencil if backface is infront of depthbuffer
1339 GL_CullFace(r_refdef.view.cullface_back);
1340 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1342 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1344 // decrement stencil if backface is behind depthbuffer
1345 GL_CullFace(r_refdef.view.cullface_front);
1346 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1347 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1348 // increment stencil if frontface is behind depthbuffer
1349 GL_CullFace(r_refdef.view.cullface_back);
1350 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1352 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1353 GL_LockArrays(0, 0);
1358 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1360 // p1, p2, p3 are in the cubemap's local coordinate system
1361 // bias = border/(size - border)
1364 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1365 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1366 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1367 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1369 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1370 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1371 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1372 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1374 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1375 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1376 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1378 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1379 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1380 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1381 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1383 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1384 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1385 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1386 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1388 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1389 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1390 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1392 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1394 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1395 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1397 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1398 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1399 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1400 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1402 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1403 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1404 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1409 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1411 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1412 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1415 VectorSubtract(maxs, mins, radius);
1416 VectorScale(radius, 0.5f, radius);
1417 VectorAdd(mins, radius, center);
1418 Matrix4x4_Transform(worldtolight, center, lightcenter);
1419 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1420 VectorSubtract(lightcenter, lightradius, pmin);
1421 VectorAdd(lightcenter, lightradius, pmax);
1423 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1424 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1425 if(ap1 > bias*an1 && ap2 > bias*an2)
1427 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1428 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1429 if(an1 > bias*ap1 && an2 > bias*ap2)
1431 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1432 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1434 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1435 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1436 if(ap1 > bias*an1 && ap2 > bias*an2)
1438 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1439 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1440 if(an1 > bias*ap1 && an2 > bias*ap2)
1442 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1443 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1445 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1446 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1447 if(ap1 > bias*an1 && ap2 > bias*an2)
1449 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1450 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1451 if(an1 > bias*ap1 && an2 > bias*ap2)
1453 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1454 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1459 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1461 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1463 // p is in the cubemap's local coordinate system
1464 // bias = border/(size - border)
1465 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1466 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1467 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1469 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1470 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1471 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1472 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1473 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1474 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1478 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1482 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1483 float scale = (size - 2*border)/size, len;
1484 float bias = border / (float)(size - border), dp, dn, ap, an;
1485 // check if cone enclosing side would cross frustum plane
1486 scale = 2 / (scale*scale + 2);
1487 for (i = 0;i < 5;i++)
1489 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1491 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1492 len = scale*VectorLength2(n);
1493 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1494 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1495 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1497 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1499 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1500 len = scale*VectorLength(n);
1501 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1502 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1503 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1505 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1506 // check if frustum corners/origin cross plane sides
1507 for (i = 0;i < 5;i++)
1509 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1510 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1511 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1512 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1513 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1514 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1515 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1516 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1517 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1518 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1520 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1523 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1531 int mask, surfacemask = 0;
1532 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1534 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1535 tend = firsttriangle + numtris;
1536 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1538 // surface box entirely inside light box, no box cull
1539 if (projectdirection)
1541 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1543 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1544 TriangleNormal(v[0], v[1], v[2], normal);
1545 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1547 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1548 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1549 surfacemask |= mask;
1552 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1553 shadowsides[numshadowsides] = mask;
1554 shadowsideslist[numshadowsides++] = t;
1561 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1563 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1564 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1566 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1567 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1568 surfacemask |= mask;
1571 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1572 shadowsides[numshadowsides] = mask;
1573 shadowsideslist[numshadowsides++] = t;
1581 // surface box not entirely inside light box, cull each triangle
1582 if (projectdirection)
1584 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1586 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1587 TriangleNormal(v[0], v[1], v[2], normal);
1588 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1589 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1591 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1592 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1593 surfacemask |= mask;
1596 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1597 shadowsides[numshadowsides] = mask;
1598 shadowsideslist[numshadowsides++] = t;
1605 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1607 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1608 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1609 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1611 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1612 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1613 surfacemask |= mask;
1616 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1617 shadowsides[numshadowsides] = mask;
1618 shadowsideslist[numshadowsides++] = t;
1627 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1629 int i, j, outtriangles = 0;
1630 int *outelement3i[6];
1631 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1633 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1634 // make sure shadowelements is big enough for this mesh
1635 if (maxshadowtriangles < outtriangles)
1636 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1638 // compute the offset and size of the separate index lists for each cubemap side
1640 for (i = 0;i < 6;i++)
1642 outelement3i[i] = shadowelements + outtriangles * 3;
1643 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1644 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1645 outtriangles += sidetotals[i];
1648 // gather up the (sparse) triangles into separate index lists for each cubemap side
1649 for (i = 0;i < numsidetris;i++)
1651 const int *element = elements + sidetris[i] * 3;
1652 for (j = 0;j < 6;j++)
1654 if (sides[i] & (1 << j))
1656 outelement3i[j][0] = element[0];
1657 outelement3i[j][1] = element[1];
1658 outelement3i[j][2] = element[2];
1659 outelement3i[j] += 3;
1664 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1667 static void R_Shadow_MakeTextures_MakeCorona(void)
1671 unsigned char pixels[32][32][4];
1672 for (y = 0;y < 32;y++)
1674 dy = (y - 15.5f) * (1.0f / 16.0f);
1675 for (x = 0;x < 32;x++)
1677 dx = (x - 15.5f) * (1.0f / 16.0f);
1678 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1679 a = bound(0, a, 255);
1680 pixels[y][x][0] = a;
1681 pixels[y][x][1] = a;
1682 pixels[y][x][2] = a;
1683 pixels[y][x][3] = 255;
1686 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1689 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1691 float dist = sqrt(x*x+y*y+z*z);
1692 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1693 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1694 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1697 static void R_Shadow_MakeTextures(void)
1700 float intensity, dist;
1702 R_Shadow_FreeShadowMaps();
1703 R_FreeTexturePool(&r_shadow_texturepool);
1704 r_shadow_texturepool = R_AllocTexturePool();
1705 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1706 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1707 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1708 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1709 for (x = 0;x <= ATTENTABLESIZE;x++)
1711 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1712 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1713 r_shadow_attentable[x] = bound(0, intensity, 1);
1715 // 1D gradient texture
1716 for (x = 0;x < ATTEN1DSIZE;x++)
1717 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1718 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);
1719 // 2D circle texture
1720 for (y = 0;y < ATTEN2DSIZE;y++)
1721 for (x = 0;x < ATTEN2DSIZE;x++)
1722 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);
1723 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);
1724 // 3D sphere texture
1725 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1727 for (z = 0;z < ATTEN3DSIZE;z++)
1728 for (y = 0;y < ATTEN3DSIZE;y++)
1729 for (x = 0;x < ATTEN3DSIZE;x++)
1730 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));
1731 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);
1734 r_shadow_attenuation3dtexture = NULL;
1737 R_Shadow_MakeTextures_MakeCorona();
1739 // Editor light sprites
1740 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1757 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1758 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1775 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1776 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1793 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1794 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1811 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1812 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1829 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1830 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1847 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1850 void R_Shadow_ValidateCvars(void)
1852 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1853 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1854 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1855 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1856 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1857 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1860 void R_Shadow_RenderMode_Begin(void)
1866 R_Shadow_ValidateCvars();
1868 if (!r_shadow_attenuation2dtexture
1869 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1870 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1871 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1872 R_Shadow_MakeTextures();
1875 R_Mesh_ColorPointer(NULL, 0, 0);
1876 R_Mesh_ResetTextureState();
1877 GL_BlendFunc(GL_ONE, GL_ZERO);
1878 GL_DepthRange(0, 1);
1879 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1881 GL_DepthMask(false);
1882 GL_Color(0, 0, 0, 1);
1883 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1885 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1887 if (gl_ext_separatestencil.integer)
1889 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1890 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1892 else if (gl_ext_stenciltwoside.integer)
1894 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1895 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1899 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1900 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1903 if (r_glsl.integer && vid.support.arb_fragment_shader)
1904 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1905 else if (vid.support.arb_texture_env_dot3 && vid.support.arb_texture_cube_map && r_shadow_dot3.integer && vid.stencil)
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1912 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1913 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1914 r_shadow_drawbuffer = drawbuffer;
1915 r_shadow_readbuffer = readbuffer;
1917 r_shadow_cullface_front = r_refdef.view.cullface_front;
1918 r_shadow_cullface_back = r_refdef.view.cullface_back;
1921 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1923 rsurface.rtlight = rtlight;
1926 void R_Shadow_RenderMode_Reset(void)
1929 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1931 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1933 if (vid.support.ext_framebuffer_object)
1935 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1938 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1939 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1941 R_SetViewport(&r_refdef.view.viewport);
1942 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1943 R_Mesh_ColorPointer(NULL, 0, 0);
1944 R_Mesh_ResetTextureState();
1945 GL_DepthRange(0, 1);
1947 GL_DepthMask(false);
1948 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1949 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1950 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1951 qglStencilMask(~0);CHECKGLERROR
1952 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1953 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1954 r_refdef.view.cullface_front = r_shadow_cullface_front;
1955 r_refdef.view.cullface_back = r_shadow_cullface_back;
1956 GL_CullFace(r_refdef.view.cullface_back);
1957 GL_Color(1, 1, 1, 1);
1958 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1959 GL_BlendFunc(GL_ONE, GL_ZERO);
1960 R_SetupGenericShader(false);
1961 r_shadow_usingshadowmaprect = false;
1962 r_shadow_usingshadowmapcube = false;
1963 r_shadow_usingshadowmap2d = false;
1967 void R_Shadow_ClearStencil(void)
1970 GL_Clear(GL_STENCIL_BUFFER_BIT);
1971 r_refdef.stats.lights_clears++;
1974 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1976 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1977 if (r_shadow_rendermode == mode)
1980 R_Shadow_RenderMode_Reset();
1981 GL_ColorMask(0, 0, 0, 0);
1982 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1983 R_SetupDepthOrShadowShader();
1984 qglDepthFunc(GL_LESS);CHECKGLERROR
1985 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1986 r_shadow_rendermode = mode;
1991 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1992 GL_CullFace(GL_NONE);
1993 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1994 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1996 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1997 GL_CullFace(GL_NONE);
1998 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1999 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2001 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2002 GL_CullFace(GL_NONE);
2003 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2004 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2005 qglStencilMask(~0);CHECKGLERROR
2006 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2007 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2008 qglStencilMask(~0);CHECKGLERROR
2009 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2011 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2012 GL_CullFace(GL_NONE);
2013 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2014 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2015 qglStencilMask(~0);CHECKGLERROR
2016 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2017 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2018 qglStencilMask(~0);CHECKGLERROR
2019 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2024 static void R_Shadow_MakeVSDCT(void)
2026 // maps to a 2x3 texture rectangle with normalized coordinates
2031 // stores abs(dir.xy), offset.xy/2.5
2032 unsigned char data[4*6] =
2034 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2035 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2036 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2037 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2038 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2039 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2041 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2044 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2048 float nearclip, farclip, bias;
2049 r_viewport_t viewport;
2052 maxsize = r_shadow_shadowmapmaxsize;
2053 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2055 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2056 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2057 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2058 r_shadow_shadowmapside = side;
2059 r_shadow_shadowmapsize = size;
2060 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2062 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2063 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2064 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2065 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2067 // complex unrolled cube approach (more flexible)
2068 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2069 R_Shadow_MakeVSDCT();
2070 if (!r_shadow_shadowmap2dtexture)
2073 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2074 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2075 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2076 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2077 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2078 // render depth into the fbo, do not render color at all
2079 qglDrawBuffer(GL_NONE);CHECKGLERROR
2080 qglReadBuffer(GL_NONE);CHECKGLERROR
2081 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2082 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2084 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2085 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2090 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2091 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2092 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2093 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2095 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2097 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2098 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2099 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2100 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2102 // complex unrolled cube approach (more flexible)
2103 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2104 R_Shadow_MakeVSDCT();
2105 if (!r_shadow_shadowmaprectangletexture)
2108 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2109 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2110 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2111 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2112 // render depth into the fbo, do not render color at all
2113 qglDrawBuffer(GL_NONE);CHECKGLERROR
2114 qglReadBuffer(GL_NONE);CHECKGLERROR
2115 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2116 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2118 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2119 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2124 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2125 r_shadow_shadowmap_texturescale[0] = 1.0f;
2126 r_shadow_shadowmap_texturescale[1] = 1.0f;
2127 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2129 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2131 r_shadow_shadowmap_parameters[0] = 1.0f;
2132 r_shadow_shadowmap_parameters[1] = 1.0f;
2133 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2134 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2136 // simple cube approach
2137 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2140 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2141 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2142 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2143 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2144 // render depth into the fbo, do not render color at all
2145 qglDrawBuffer(GL_NONE);CHECKGLERROR
2146 qglReadBuffer(GL_NONE);CHECKGLERROR
2147 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2148 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2150 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2151 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2156 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2157 r_shadow_shadowmap_texturescale[0] = 0.0f;
2158 r_shadow_shadowmap_texturescale[1] = 0.0f;
2159 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2162 R_Shadow_RenderMode_Reset();
2165 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2166 R_SetupDepthOrShadowShader();
2170 R_SetupShowDepthShader();
2171 qglClearColor(1,1,1,1);CHECKGLERROR
2174 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2181 R_SetViewport(&viewport);
2182 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2183 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2185 int flipped = (side&1)^(side>>2);
2186 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2187 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2188 GL_CullFace(r_refdef.view.cullface_back);
2190 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2192 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2195 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2199 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2203 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2204 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2205 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2206 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2209 R_Shadow_RenderMode_Reset();
2210 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2213 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2217 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2218 // only draw light where this geometry was already rendered AND the
2219 // stencil is 128 (values other than this mean shadow)
2220 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2222 r_shadow_rendermode = r_shadow_lightingrendermode;
2223 // do global setup needed for the chosen lighting mode
2224 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2226 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2227 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2231 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2233 r_shadow_usingshadowmap2d = true;
2234 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2237 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2239 r_shadow_usingshadowmaprect = true;
2240 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2243 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2245 r_shadow_usingshadowmapcube = true;
2246 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2250 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2252 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2257 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2258 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2259 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2263 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2266 R_Shadow_RenderMode_Reset();
2267 GL_BlendFunc(GL_ONE, GL_ONE);
2268 GL_DepthRange(0, 1);
2269 GL_DepthTest(r_showshadowvolumes.integer < 2);
2270 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2271 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2272 GL_CullFace(GL_NONE);
2273 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2276 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2279 R_Shadow_RenderMode_Reset();
2280 GL_BlendFunc(GL_ONE, GL_ONE);
2281 GL_DepthRange(0, 1);
2282 GL_DepthTest(r_showlighting.integer < 2);
2283 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2286 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2290 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2291 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2293 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2296 void R_Shadow_RenderMode_End(void)
2299 R_Shadow_RenderMode_Reset();
2300 R_Shadow_RenderMode_ActiveLight(NULL);
2302 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2303 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2306 int bboxedges[12][2] =
2325 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2327 int i, ix1, iy1, ix2, iy2;
2328 float x1, y1, x2, y2;
2330 float vertex[20][3];
2339 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2340 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2341 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2342 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2344 if (!r_shadow_scissor.integer)
2347 // if view is inside the light box, just say yes it's visible
2348 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2351 x1 = y1 = x2 = y2 = 0;
2353 // transform all corners that are infront of the nearclip plane
2354 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2355 plane4f[3] = r_refdef.view.frustum[4].dist;
2357 for (i = 0;i < 8;i++)
2359 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2360 dist[i] = DotProduct4(corner[i], plane4f);
2361 sign[i] = dist[i] > 0;
2364 VectorCopy(corner[i], vertex[numvertices]);
2368 // if some points are behind the nearclip, add clipped edge points to make
2369 // sure that the scissor boundary is complete
2370 if (numvertices > 0 && numvertices < 8)
2372 // add clipped edge points
2373 for (i = 0;i < 12;i++)
2375 j = bboxedges[i][0];
2376 k = bboxedges[i][1];
2377 if (sign[j] != sign[k])
2379 f = dist[j] / (dist[j] - dist[k]);
2380 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2386 // if we have no points to check, the light is behind the view plane
2390 // if we have some points to transform, check what screen area is covered
2391 x1 = y1 = x2 = y2 = 0;
2393 //Con_Printf("%i vertices to transform...\n", numvertices);
2394 for (i = 0;i < numvertices;i++)
2396 VectorCopy(vertex[i], v);
2397 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2398 //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]);
2401 if (x1 > v2[0]) x1 = v2[0];
2402 if (x2 < v2[0]) x2 = v2[0];
2403 if (y1 > v2[1]) y1 = v2[1];
2404 if (y2 < v2[1]) y2 = v2[1];
2413 // now convert the scissor rectangle to integer screen coordinates
2414 ix1 = (int)(x1 - 1.0f);
2415 iy1 = vid.height - (int)(y2 - 1.0f);
2416 ix2 = (int)(x2 + 1.0f);
2417 iy2 = vid.height - (int)(y1 + 1.0f);
2418 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2420 // clamp it to the screen
2421 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2422 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2423 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2424 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2426 // if it is inside out, it's not visible
2427 if (ix2 <= ix1 || iy2 <= iy1)
2430 // the light area is visible, set up the scissor rectangle
2431 r_shadow_lightscissor[0] = ix1;
2432 r_shadow_lightscissor[1] = iy1;
2433 r_shadow_lightscissor[2] = ix2 - ix1;
2434 r_shadow_lightscissor[3] = iy2 - iy1;
2436 r_refdef.stats.lights_scissored++;
2440 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2442 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2443 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2444 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2445 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2446 if (r_textureunits.integer >= 3)
2448 if (VectorLength2(diffusecolor) > 0)
2450 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2452 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2453 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2454 if ((dot = DotProduct(n, v)) < 0)
2456 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2457 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2460 VectorCopy(ambientcolor, color4f);
2461 if (r_refdef.fogenabled)
2464 f = RSurf_FogVertex(vertex3f);
2465 VectorScale(color4f, f, color4f);
2472 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2474 VectorCopy(ambientcolor, color4f);
2475 if (r_refdef.fogenabled)
2478 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2479 f = RSurf_FogVertex(vertex3f);
2480 VectorScale(color4f, f, color4f);
2486 else if (r_textureunits.integer >= 2)
2488 if (VectorLength2(diffusecolor) > 0)
2490 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2492 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2493 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2495 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2496 if ((dot = DotProduct(n, v)) < 0)
2498 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2499 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2500 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2501 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2505 color4f[0] = ambientcolor[0] * distintensity;
2506 color4f[1] = ambientcolor[1] * distintensity;
2507 color4f[2] = ambientcolor[2] * distintensity;
2509 if (r_refdef.fogenabled)
2512 f = RSurf_FogVertex(vertex3f);
2513 VectorScale(color4f, f, color4f);
2517 VectorClear(color4f);
2523 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2525 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2526 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2528 color4f[0] = ambientcolor[0] * distintensity;
2529 color4f[1] = ambientcolor[1] * distintensity;
2530 color4f[2] = ambientcolor[2] * distintensity;
2531 if (r_refdef.fogenabled)
2534 f = RSurf_FogVertex(vertex3f);
2535 VectorScale(color4f, f, color4f);
2539 VectorClear(color4f);
2546 if (VectorLength2(diffusecolor) > 0)
2548 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2550 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2551 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2553 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2554 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2555 if ((dot = DotProduct(n, v)) < 0)
2557 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2558 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2559 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2560 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2564 color4f[0] = ambientcolor[0] * distintensity;
2565 color4f[1] = ambientcolor[1] * distintensity;
2566 color4f[2] = ambientcolor[2] * distintensity;
2568 if (r_refdef.fogenabled)
2571 f = RSurf_FogVertex(vertex3f);
2572 VectorScale(color4f, f, color4f);
2576 VectorClear(color4f);
2582 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2584 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2585 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2587 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2588 color4f[0] = ambientcolor[0] * distintensity;
2589 color4f[1] = ambientcolor[1] * distintensity;
2590 color4f[2] = ambientcolor[2] * distintensity;
2591 if (r_refdef.fogenabled)
2594 f = RSurf_FogVertex(vertex3f);
2595 VectorScale(color4f, f, color4f);
2599 VectorClear(color4f);
2606 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2608 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2611 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2612 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2613 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2614 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2615 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2617 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2619 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2620 // the cubemap normalizes this for us
2621 out3f[0] = DotProduct(svector3f, lightdir);
2622 out3f[1] = DotProduct(tvector3f, lightdir);
2623 out3f[2] = DotProduct(normal3f, lightdir);
2627 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2630 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2631 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2632 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2633 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2634 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2635 float lightdir[3], eyedir[3], halfdir[3];
2636 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2638 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2639 VectorNormalize(lightdir);
2640 VectorSubtract(rsurface.localvieworigin, vertex3f, eyedir);
2641 VectorNormalize(eyedir);
2642 VectorAdd(lightdir, eyedir, halfdir);
2643 // the cubemap normalizes this for us
2644 out3f[0] = DotProduct(svector3f, halfdir);
2645 out3f[1] = DotProduct(tvector3f, halfdir);
2646 out3f[2] = DotProduct(normal3f, halfdir);
2650 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)
2652 // used to display how many times a surface is lit for level design purposes
2653 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2656 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)
2658 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2659 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2660 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2661 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2663 R_Mesh_ColorPointer(NULL, 0, 0);
2664 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2665 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2666 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2667 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2668 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2669 if (rsurface.texture->backgroundcurrentskinframe)
2671 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2672 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2673 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2674 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2676 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2677 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2678 if(rsurface.texture->colormapping)
2680 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2681 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2683 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2684 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2685 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2686 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2687 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2688 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2690 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2692 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2693 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2695 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2699 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)
2701 // shared final code for all the dot3 layers
2703 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2704 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2706 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2707 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2711 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)
2714 // colorscale accounts for how much we multiply the brightness
2717 // mult is how many times the final pass of the lighting will be
2718 // performed to get more brightness than otherwise possible.
2720 // Limit mult to 64 for sanity sake.
2722 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2724 // 3 3D combine path (Geforce3, Radeon 8500)
2725 memset(&m, 0, sizeof(m));
2726 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2727 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2728 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2729 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2730 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2731 m.tex[1] = R_GetTexture(basetexture);
2732 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2733 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2734 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2735 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2736 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2737 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2738 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2739 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2740 m.texmatrix[2] = rsurface.entitytolight;
2741 GL_BlendFunc(GL_ONE, GL_ONE);
2743 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2745 // 2 3D combine path (Geforce3, original Radeon)
2746 memset(&m, 0, sizeof(m));
2747 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2748 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2749 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2750 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2751 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2752 m.tex[1] = R_GetTexture(basetexture);
2753 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2754 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2755 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2756 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2757 GL_BlendFunc(GL_ONE, GL_ONE);
2759 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2761 // 4 2D combine path (Geforce3, Radeon 8500)
2762 memset(&m, 0, sizeof(m));
2763 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2764 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2765 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2766 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2767 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2768 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2769 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2770 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2771 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2772 m.texmatrix[1] = rsurface.entitytoattenuationz;
2773 m.tex[2] = R_GetTexture(basetexture);
2774 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2775 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2776 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2777 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2778 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2780 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2781 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2782 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2783 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2784 m.texmatrix[3] = rsurface.entitytolight;
2786 GL_BlendFunc(GL_ONE, GL_ONE);
2788 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2790 // 3 2D combine path (Geforce3, original Radeon)
2791 memset(&m, 0, sizeof(m));
2792 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2793 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2794 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2795 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2796 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2797 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2798 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2799 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2800 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2801 m.texmatrix[1] = rsurface.entitytoattenuationz;
2802 m.tex[2] = R_GetTexture(basetexture);
2803 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2804 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2805 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2806 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2807 GL_BlendFunc(GL_ONE, GL_ONE);
2811 // 2/2/2 2D combine path (any dot3 card)
2812 memset(&m, 0, sizeof(m));
2813 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2814 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2815 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2816 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2817 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2818 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2819 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2820 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2821 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2822 m.texmatrix[1] = rsurface.entitytoattenuationz;
2823 R_Mesh_TextureState(&m);
2824 GL_ColorMask(0,0,0,1);
2825 GL_BlendFunc(GL_ONE, GL_ZERO);
2826 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2829 memset(&m, 0, sizeof(m));
2830 m.tex[0] = R_GetTexture(basetexture);
2831 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2832 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2833 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2834 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2835 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2837 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2838 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2839 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2840 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2841 m.texmatrix[1] = rsurface.entitytolight;
2843 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2845 // this final code is shared
2846 R_Mesh_TextureState(&m);
2847 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);
2850 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)
2853 // colorscale accounts for how much we multiply the brightness
2856 // mult is how many times the final pass of the lighting will be
2857 // performed to get more brightness than otherwise possible.
2859 // Limit mult to 64 for sanity sake.
2861 // generate normalization cubemap texcoords
2862 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2863 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2865 // 3/2 3D combine path (Geforce3, Radeon 8500)
2866 memset(&m, 0, sizeof(m));
2867 m.tex[0] = R_GetTexture(normalmaptexture);
2868 m.texcombinergb[0] = GL_REPLACE;
2869 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2870 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2871 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2872 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2873 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2874 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2875 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2876 m.pointer_texcoord_bufferobject[1] = 0;
2877 m.pointer_texcoord_bufferoffset[1] = 0;
2878 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2879 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2880 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2881 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2882 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2883 R_Mesh_TextureState(&m);
2884 GL_ColorMask(0,0,0,1);
2885 GL_BlendFunc(GL_ONE, GL_ZERO);
2886 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2889 memset(&m, 0, sizeof(m));
2890 m.tex[0] = R_GetTexture(basetexture);
2891 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2892 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2893 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2894 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2895 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2897 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2898 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2899 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2900 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2901 m.texmatrix[1] = rsurface.entitytolight;
2903 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2905 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2907 // 1/2/2 3D combine path (original Radeon)
2908 memset(&m, 0, sizeof(m));
2909 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2910 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2911 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2912 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2913 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2914 R_Mesh_TextureState(&m);
2915 GL_ColorMask(0,0,0,1);
2916 GL_BlendFunc(GL_ONE, GL_ZERO);
2917 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2920 memset(&m, 0, sizeof(m));
2921 m.tex[0] = R_GetTexture(normalmaptexture);
2922 m.texcombinergb[0] = GL_REPLACE;
2923 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2924 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2925 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2926 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2927 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2928 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2929 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2930 m.pointer_texcoord_bufferobject[1] = 0;
2931 m.pointer_texcoord_bufferoffset[1] = 0;
2932 R_Mesh_TextureState(&m);
2933 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2934 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2937 memset(&m, 0, sizeof(m));
2938 m.tex[0] = R_GetTexture(basetexture);
2939 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2940 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2941 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2942 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2943 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2945 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2946 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2947 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2948 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2949 m.texmatrix[1] = rsurface.entitytolight;
2951 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2953 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2955 // 2/2 3D combine path (original Radeon)
2956 memset(&m, 0, sizeof(m));
2957 m.tex[0] = R_GetTexture(normalmaptexture);
2958 m.texcombinergb[0] = GL_REPLACE;
2959 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2960 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2961 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2962 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2963 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2964 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2965 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2966 m.pointer_texcoord_bufferobject[1] = 0;
2967 m.pointer_texcoord_bufferoffset[1] = 0;
2968 R_Mesh_TextureState(&m);
2969 GL_ColorMask(0,0,0,1);
2970 GL_BlendFunc(GL_ONE, GL_ZERO);
2971 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2974 memset(&m, 0, sizeof(m));
2975 m.tex[0] = R_GetTexture(basetexture);
2976 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2977 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2978 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2979 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2980 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2981 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2982 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2983 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2984 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2985 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2987 else if (r_textureunits.integer >= 4)
2989 // 4/2 2D combine path (Geforce3, Radeon 8500)
2990 memset(&m, 0, sizeof(m));
2991 m.tex[0] = R_GetTexture(normalmaptexture);
2992 m.texcombinergb[0] = GL_REPLACE;
2993 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2994 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2995 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2996 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2997 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2998 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2999 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3000 m.pointer_texcoord_bufferobject[1] = 0;
3001 m.pointer_texcoord_bufferoffset[1] = 0;
3002 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3003 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3004 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3005 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3006 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
3007 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
3008 m.pointer_texcoord3f[3] = rsurface.vertex3f;
3009 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
3010 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
3011 m.texmatrix[3] = rsurface.entitytoattenuationz;
3012 R_Mesh_TextureState(&m);
3013 GL_ColorMask(0,0,0,1);
3014 GL_BlendFunc(GL_ONE, GL_ZERO);
3015 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3018 memset(&m, 0, sizeof(m));
3019 m.tex[0] = R_GetTexture(basetexture);
3020 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3021 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3022 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3023 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3024 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3026 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3027 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3028 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3029 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3030 m.texmatrix[1] = rsurface.entitytolight;
3032 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3036 // 2/2/2 2D combine path (any dot3 card)
3037 memset(&m, 0, sizeof(m));
3038 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3039 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3040 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3041 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3042 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3043 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3044 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3045 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3046 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3047 m.texmatrix[1] = rsurface.entitytoattenuationz;
3048 R_Mesh_TextureState(&m);
3049 GL_ColorMask(0,0,0,1);
3050 GL_BlendFunc(GL_ONE, GL_ZERO);
3051 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3054 memset(&m, 0, sizeof(m));
3055 m.tex[0] = R_GetTexture(normalmaptexture);
3056 m.texcombinergb[0] = GL_REPLACE;
3057 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3058 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3059 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3060 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3061 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3062 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3063 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3064 m.pointer_texcoord_bufferobject[1] = 0;
3065 m.pointer_texcoord_bufferoffset[1] = 0;
3066 R_Mesh_TextureState(&m);
3067 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3068 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3071 memset(&m, 0, sizeof(m));
3072 m.tex[0] = R_GetTexture(basetexture);
3073 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3074 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3075 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3076 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3077 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3079 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3080 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3081 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3082 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3083 m.texmatrix[1] = rsurface.entitytolight;
3085 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3087 // this final code is shared
3088 R_Mesh_TextureState(&m);
3089 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);
3092 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)
3094 float glossexponent;
3096 // FIXME: detect blendsquare!
3097 //if (!gl_support_blendsquare)
3100 // generate normalization cubemap texcoords
3101 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
3102 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
3104 // 2/0/0/1/2 3D combine blendsquare path
3105 memset(&m, 0, sizeof(m));
3106 m.tex[0] = R_GetTexture(normalmaptexture);
3107 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3108 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3109 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3110 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3111 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3112 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3113 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3114 m.pointer_texcoord_bufferobject[1] = 0;
3115 m.pointer_texcoord_bufferoffset[1] = 0;
3116 R_Mesh_TextureState(&m);
3117 GL_ColorMask(0,0,0,1);
3118 // this squares the result
3119 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3120 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3122 // second and third pass
3123 R_Mesh_ResetTextureState();
3124 // square alpha in framebuffer a few times to make it shiny
3125 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3126 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3127 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3130 memset(&m, 0, sizeof(m));
3131 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
3132 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3133 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3134 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3135 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3136 R_Mesh_TextureState(&m);
3137 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3138 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3141 memset(&m, 0, sizeof(m));
3142 m.tex[0] = R_GetTexture(glosstexture);
3143 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3144 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3145 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3146 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3147 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3149 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3150 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3151 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3152 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3153 m.texmatrix[1] = rsurface.entitytolight;
3155 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3157 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3159 // 2/0/0/2 3D combine blendsquare path
3160 memset(&m, 0, sizeof(m));
3161 m.tex[0] = R_GetTexture(normalmaptexture);
3162 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3163 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3164 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3165 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3166 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3167 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3168 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3169 m.pointer_texcoord_bufferobject[1] = 0;
3170 m.pointer_texcoord_bufferoffset[1] = 0;
3171 R_Mesh_TextureState(&m);
3172 GL_ColorMask(0,0,0,1);
3173 // this squares the result
3174 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3175 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3177 // second and third pass
3178 R_Mesh_ResetTextureState();
3179 // square alpha in framebuffer a few times to make it shiny
3180 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3181 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3182 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3185 memset(&m, 0, sizeof(m));
3186 m.tex[0] = R_GetTexture(glosstexture);
3187 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3188 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3189 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3190 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3191 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3192 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3193 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3194 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3195 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3196 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3200 // 2/0/0/2/2 2D combine blendsquare path
3201 memset(&m, 0, sizeof(m));
3202 m.tex[0] = R_GetTexture(normalmaptexture);
3203 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3204 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3205 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3206 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3207 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3208 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3209 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3210 m.pointer_texcoord_bufferobject[1] = 0;
3211 m.pointer_texcoord_bufferoffset[1] = 0;
3212 R_Mesh_TextureState(&m);
3213 GL_ColorMask(0,0,0,1);
3214 // this squares the result
3215 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3216 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3218 // second and third pass
3219 R_Mesh_ResetTextureState();
3220 // square alpha in framebuffer a few times to make it shiny
3221 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3222 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3223 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3226 memset(&m, 0, sizeof(m));
3227 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3228 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3229 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3230 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3231 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3232 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3233 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3234 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3235 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3236 m.texmatrix[1] = rsurface.entitytoattenuationz;
3237 R_Mesh_TextureState(&m);
3238 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3239 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3242 memset(&m, 0, sizeof(m));
3243 m.tex[0] = R_GetTexture(glosstexture);
3244 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3245 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3246 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3247 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3248 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3250 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3251 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3252 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3253 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3254 m.texmatrix[1] = rsurface.entitytolight;
3256 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3258 // this final code is shared
3259 R_Mesh_TextureState(&m);
3260 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);
3263 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)
3265 // ARB path (any Geforce, any Radeon)
3266 qboolean doambient = ambientscale > 0;
3267 qboolean dodiffuse = diffusescale > 0;
3268 qboolean dospecular = specularscale > 0;
3269 if (!doambient && !dodiffuse && !dospecular)
3271 R_Mesh_ColorPointer(NULL, 0, 0);
3273 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3275 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3279 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3281 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3286 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3288 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3291 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3294 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3301 int newnumtriangles;
3305 int maxtriangles = 4096;
3306 int newelements[4096*3];
3307 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3308 for (renders = 0;renders < 64;renders++)
3313 newnumtriangles = 0;
3315 // due to low fillrate on the cards this vertex lighting path is
3316 // designed for, we manually cull all triangles that do not
3317 // contain a lit vertex
3318 // this builds batches of triangles from multiple surfaces and
3319 // renders them at once
3320 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3322 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3324 if (newnumtriangles)
3326 newfirstvertex = min(newfirstvertex, e[0]);
3327 newlastvertex = max(newlastvertex, e[0]);
3331 newfirstvertex = e[0];
3332 newlastvertex = e[0];
3334 newfirstvertex = min(newfirstvertex, e[1]);
3335 newlastvertex = max(newlastvertex, e[1]);
3336 newfirstvertex = min(newfirstvertex, e[2]);
3337 newlastvertex = max(newlastvertex, e[2]);
3343 if (newnumtriangles >= maxtriangles)
3345 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3346 newnumtriangles = 0;
3352 if (newnumtriangles >= 1)
3354 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3357 // if we couldn't find any lit triangles, exit early
3360 // now reduce the intensity for the next overbright pass
3361 // we have to clamp to 0 here incase the drivers have improper
3362 // handling of negative colors
3363 // (some old drivers even have improper handling of >1 color)
3365 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3367 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3369 c[0] = max(0, c[0] - 1);
3370 c[1] = max(0, c[1] - 1);
3371 c[2] = max(0, c[2] - 1);
3383 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)
3385 // OpenGL 1.1 path (anything)
3386 float ambientcolorbase[3], diffusecolorbase[3];
3387 float ambientcolorpants[3], diffusecolorpants[3];
3388 float ambientcolorshirt[3], diffusecolorshirt[3];
3390 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3391 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3392 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3393 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3394 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3395 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3396 memset(&m, 0, sizeof(m));
3397 m.tex[0] = R_GetTexture(basetexture);
3398 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3399 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3400 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3401 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3402 if (r_textureunits.integer >= 2)
3405 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3406 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3407 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3408 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3409 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3410 if (r_textureunits.integer >= 3)
3412 // Voodoo4 or Kyro (or Geforce3/Radeon with r_shadow_dot3 off)
3413 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3414 m.texmatrix[2] = rsurface.entitytoattenuationz;
3415 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3416 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3417 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3420 R_Mesh_TextureState(&m);
3421 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3422 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3425 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3426 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3430 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3431 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3435 extern cvar_t gl_lightmaps;
3436 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)
3438 float ambientscale, diffusescale, specularscale;
3440 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3442 // calculate colors to render this texture with
3443 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3444 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3445 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3446 ambientscale = rsurface.rtlight->ambientscale;
3447 diffusescale = rsurface.rtlight->diffusescale;
3448 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3449 if (!r_shadow_usenormalmap.integer)
3451 ambientscale += 1.0f * diffusescale;
3455 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3457 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
3460 VectorNegate(lightcolorbase, lightcolorbase);
3461 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3463 RSurf_SetupDepthAndCulling();
3464 nmap = rsurface.texture->currentskinframe->nmap;
3465 if (gl_lightmaps.integer)
3466 nmap = r_texture_blanknormalmap;
3467 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3469 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3470 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3473 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3474 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3475 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3478 VectorClear(lightcolorpants);
3481 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3482 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3483 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3486 VectorClear(lightcolorshirt);
3487 switch (r_shadow_rendermode)
3489 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3490 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3491 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);
3493 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3494 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);
3496 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3497 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);
3499 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3500 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);
3503 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3509 switch (r_shadow_rendermode)
3511 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3512 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3513 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);
3515 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3516 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);
3518 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3519 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);
3521 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3522 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);
3525 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3530 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3533 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)
3535 matrix4x4_t tempmatrix = *matrix;
3536 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3538 // if this light has been compiled before, free the associated data
3539 R_RTLight_Uncompile(rtlight);
3541 // clear it completely to avoid any lingering data
3542 memset(rtlight, 0, sizeof(*rtlight));
3544 // copy the properties
3545 rtlight->matrix_lighttoworld = tempmatrix;
3546 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3547 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3548 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3549 VectorCopy(color, rtlight->color);
3550 rtlight->cubemapname[0] = 0;
3551 if (cubemapname && cubemapname[0])
3552 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3553 rtlight->shadow = shadow;
3554 rtlight->corona = corona;
3555 rtlight->style = style;
3556 rtlight->isstatic = isstatic;
3557 rtlight->coronasizescale = coronasizescale;
3558 rtlight->ambientscale = ambientscale;
3559 rtlight->diffusescale = diffusescale;
3560 rtlight->specularscale = specularscale;
3561 rtlight->flags = flags;
3563 // compute derived data
3564 //rtlight->cullradius = rtlight->radius;
3565 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3566 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3567 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3568 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3569 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3570 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3571 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3574 // compiles rtlight geometry
3575 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3576 void R_RTLight_Compile(rtlight_t *rtlight)
3579 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3580 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3581 entity_render_t *ent = r_refdef.scene.worldentity;
3582 dp_model_t *model = r_refdef.scene.worldmodel;
3583 unsigned char *data;
3586 // compile the light
3587 rtlight->compiled = true;
3588 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3589 rtlight->static_numleafs = 0;
3590 rtlight->static_numleafpvsbytes = 0;
3591 rtlight->static_leaflist = NULL;
3592 rtlight->static_leafpvs = NULL;
3593 rtlight->static_numsurfaces = 0;
3594 rtlight->static_surfacelist = NULL;
3595 rtlight->static_shadowmap_receivers = 0x3F;
3596 rtlight->static_shadowmap_casters = 0x3F;
3597 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3598 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3599 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3600 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3601 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3602 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3604 if (model && model->GetLightInfo)
3606 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3607 r_shadow_compilingrtlight = rtlight;
3608 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);
3609 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);
3610 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3611 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3612 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3613 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3614 rtlight->static_numsurfaces = numsurfaces;
3615 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3616 rtlight->static_numleafs = numleafs;
3617 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3618 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3619 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3620 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3621 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3622 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3623 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3624 if (rtlight->static_numsurfaces)
3625 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3626 if (rtlight->static_numleafs)
3627 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3628 if (rtlight->static_numleafpvsbytes)
3629 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3630 if (rtlight->static_numshadowtrispvsbytes)
3631 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3632 if (rtlight->static_numlighttrispvsbytes)
3633 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3634 switch (rtlight->shadowmode)
3636 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3637 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3638 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3639 if (model->CompileShadowMap && rtlight->shadow)
3640 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3643 if (model->CompileShadowVolume && rtlight->shadow)
3644 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3647 // now we're done compiling the rtlight
3648 r_shadow_compilingrtlight = NULL;
3652 // use smallest available cullradius - box radius or light radius
3653 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3654 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3656 shadowzpasstris = 0;
3657 if (rtlight->static_meshchain_shadow_zpass)
3658 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3659 shadowzpasstris += mesh->numtriangles;
3661 shadowzfailtris = 0;
3662 if (rtlight->static_meshchain_shadow_zfail)
3663 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3664 shadowzfailtris += mesh->numtriangles;
3667 if (rtlight->static_numlighttrispvsbytes)
3668 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3669 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3673 if (rtlight->static_numlighttrispvsbytes)
3674 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3675 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3678 if (developer.integer >= 10)
3679 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);
3682 void R_RTLight_Uncompile(rtlight_t *rtlight)
3684 if (rtlight->compiled)
3686 if (rtlight->static_meshchain_shadow_zpass)
3687 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3688 rtlight->static_meshchain_shadow_zpass = NULL;
3689 if (rtlight->static_meshchain_shadow_zfail)
3690 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3691 rtlight->static_meshchain_shadow_zfail = NULL;
3692 if (rtlight->static_meshchain_shadow_shadowmap)
3693 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3694 rtlight->static_meshchain_shadow_shadowmap = NULL;
3695 // these allocations are grouped
3696 if (rtlight->static_surfacelist)
3697 Mem_Free(rtlight->static_surfacelist);
3698 rtlight->static_numleafs = 0;
3699 rtlight->static_numleafpvsbytes = 0;
3700 rtlight->static_leaflist = NULL;
3701 rtlight->static_leafpvs = NULL;
3702 rtlight->static_numsurfaces = 0;
3703 rtlight->static_surfacelist = NULL;
3704 rtlight->static_numshadowtrispvsbytes = 0;
3705 rtlight->static_shadowtrispvs = NULL;
3706 rtlight->static_numlighttrispvsbytes = 0;
3707 rtlight->static_lighttrispvs = NULL;
3708 rtlight->compiled = false;
3712 void R_Shadow_UncompileWorldLights(void)
3716 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3717 for (lightindex = 0;lightindex < range;lightindex++)
3719 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3722 R_RTLight_Uncompile(&light->rtlight);
3726 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3730 // reset the count of frustum planes
3731 // see rsurface.rtlight_frustumplanes definition for how much this array
3733 rsurface.rtlight_numfrustumplanes = 0;
3735 // haven't implemented a culling path for ortho rendering
3736 if (!r_refdef.view.useperspective)
3738 // check if the light is on screen and copy the 4 planes if it is
3739 for (i = 0;i < 4;i++)
3740 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3743 for (i = 0;i < 4;i++)
3744 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3749 // generate a deformed frustum that includes the light origin, this is
3750 // used to cull shadow casting surfaces that can not possibly cast a
3751 // shadow onto the visible light-receiving surfaces, which can be a
3754 // if the light origin is onscreen the result will be 4 planes exactly
3755 // if the light origin is offscreen on only one axis the result will
3756 // be exactly 5 planes (split-side case)
3757 // if the light origin is offscreen on two axes the result will be
3758 // exactly 4 planes (stretched corner case)
3759 for (i = 0;i < 4;i++)
3761 // quickly reject standard frustum planes that put the light
3762 // origin outside the frustum
3763 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3766 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3768 // if all the standard frustum planes were accepted, the light is onscreen
3769 // otherwise we need to generate some more planes below...
3770 if (rsurface.rtlight_numfrustumplanes < 4)
3772 // at least one of the stock frustum planes failed, so we need to
3773 // create one or two custom planes to enclose the light origin
3774 for (i = 0;i < 4;i++)
3776 // create a plane using the view origin and light origin, and a
3777 // single point from the frustum corner set
3778 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3779 VectorNormalize(plane.normal);
3780 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3781 // see if this plane is backwards and flip it if so
3782 for (j = 0;j < 4;j++)
3783 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3787 VectorNegate(plane.normal, plane.normal);
3789 // flipped plane, test again to see if it is now valid
3790 for (j = 0;j < 4;j++)
3791 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3793 // if the plane is still not valid, then it is dividing the
3794 // frustum and has to be rejected
3798 // we have created a valid plane, compute extra info
3799 PlaneClassify(&plane);
3801 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3803 // if we've found 5 frustum planes then we have constructed a
3804 // proper split-side case and do not need to keep searching for
3805 // planes to enclose the light origin
3806 if (rsurface.rtlight_numfrustumplanes == 5)
3814 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3816 plane = rsurface.rtlight_frustumplanes[i];
3817 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));
3822 // now add the light-space box planes if the light box is rotated, as any
3823 // caster outside the oriented light box is irrelevant (even if it passed
3824 // the worldspace light box, which is axial)
3825 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3827 for (i = 0;i < 6;i++)
3831 v[i >> 1] = (i & 1) ? -1 : 1;
3832 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3833 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3834 plane.dist = VectorNormalizeLength(plane.normal);
3835 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3836 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3842 // add the world-space reduced box planes
3843 for (i = 0;i < 6;i++)
3845 VectorClear(plane.normal);
3846 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3847 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3848 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3857 // reduce all plane distances to tightly fit the rtlight cull box, which
3859 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3860 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3861 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3862 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3863 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3864 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3865 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3866 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3867 oldnum = rsurface.rtlight_numfrustumplanes;
3868 rsurface.rtlight_numfrustumplanes = 0;
3869 for (j = 0;j < oldnum;j++)
3871 // find the nearest point on the box to this plane
3872 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3873 for (i = 1;i < 8;i++)
3875 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3876 if (bestdist > dist)
3879 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);
3880 // if the nearest point is near or behind the plane, we want this
3881 // plane, otherwise the plane is useless as it won't cull anything
3882 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3884 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3885 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3892 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3896 RSurf_ActiveWorldEntity();
3898 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3901 GL_CullFace(GL_NONE);
3902 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3903 for (;mesh;mesh = mesh->next)
3905 if (!mesh->sidetotals[r_shadow_shadowmapside])
3907 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3908 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3909 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3913 else if (r_refdef.scene.worldentity->model)
3914 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3916 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3919 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3924 int surfacelistindex;
3925 msurface_t *surface;
3927 RSurf_ActiveWorldEntity();
3929 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3932 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3933 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3934 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3935 for (;mesh;mesh = mesh->next)
3937 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3938 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3939 GL_LockArrays(0, mesh->numverts);
3940 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3942 // increment stencil if frontface is infront of depthbuffer
3943 GL_CullFace(r_refdef.view.cullface_back);
3944 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3945 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3946 // decrement stencil if backface is infront of depthbuffer
3947 GL_CullFace(r_refdef.view.cullface_front);
3948 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3950 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3952 // decrement stencil if backface is behind depthbuffer
3953 GL_CullFace(r_refdef.view.cullface_front);
3954 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3955 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3956 // increment stencil if frontface is behind depthbuffer
3957 GL_CullFace(r_refdef.view.cullface_back);
3958 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3960 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3961 GL_LockArrays(0, 0);
3965 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3967 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3968 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3970 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3971 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3972 if (CHECKPVSBIT(trispvs, t))
3973 shadowmarklist[numshadowmark++] = t;
3975 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);
3977 else if (numsurfaces)
3978 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3980 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3983 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3985 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3986 vec_t relativeshadowradius;
3987 RSurf_ActiveModelEntity(ent, false, false);
3988 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3989 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3990 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3991 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3992 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3993 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3994 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3995 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3996 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3998 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4001 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4002 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4005 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4007 // set up properties for rendering light onto this entity
4008 RSurf_ActiveModelEntity(ent, true, true);
4009 GL_AlphaTest(false);
4010 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4011 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4012 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4013 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4014 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
4015 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
4018 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4020 if (!r_refdef.scene.worldmodel->DrawLight)
4023 // set up properties for rendering light onto this entity
4024 RSurf_ActiveWorldEntity();
4025 GL_AlphaTest(false);
4026 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4027 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4028 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4029 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4030 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
4031 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
4033 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
4035 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4038 void R_Shadow_DrawEntityLight(entity_render_t *ent)
4040 dp_model_t *model = ent->model;
4041 if (!model->DrawLight)
4044 R_Shadow_SetupEntityLight(ent);
4046 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4048 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4051 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
4055 int numleafs, numsurfaces;
4056 int *leaflist, *surfacelist;
4057 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
4058 int numlightentities;
4059 int numlightentities_noselfshadow;
4060 int numshadowentities;
4061 int numshadowentities_noselfshadow;
4062 static entity_render_t *lightentities[MAX_EDICTS];
4063 static entity_render_t *shadowentities[MAX_EDICTS];
4064 static unsigned char entitysides[MAX_EDICTS];
4065 int lightentities_noselfshadow;
4066 int shadowentities_noselfshadow;
4067 vec3_t nearestpoint;
4069 qboolean castshadows;
4072 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4073 // skip lights that are basically invisible (color 0 0 0)
4074 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
4077 // loading is done before visibility checks because loading should happen
4078 // all at once at the start of a level, not when it stalls gameplay.
4079 // (especially important to benchmarks)
4081 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4083 if (rtlight->compiled)
4084 R_RTLight_Uncompile(rtlight);
4085 R_RTLight_Compile(rtlight);
4089 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
4091 // look up the light style value at this time
4092 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4093 VectorScale(rtlight->color, f, rtlight->currentcolor);
4095 if (rtlight->selected)
4097 f = 2 + sin(realtime * M_PI * 4.0);
4098 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4102 // if lightstyle is currently off, don't draw the light
4103 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4106 // if the light box is offscreen, skip it
4107 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4110 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
4111 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
4113 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4115 // compiled light, world available and can receive realtime lighting
4116 // retrieve leaf information
4117 numleafs = rtlight->static_numleafs;
4118 leaflist = rtlight->static_leaflist;
4119 leafpvs = rtlight->static_leafpvs;
4120 numsurfaces = rtlight->static_numsurfaces;
4121 surfacelist = rtlight->static_surfacelist;
4122 surfacesides = NULL;
4123 shadowtrispvs = rtlight->static_shadowtrispvs;
4124 lighttrispvs = rtlight->static_lighttrispvs;
4126 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4128 // dynamic light, world available and can receive realtime lighting
4129 // calculate lit surfaces and leafs
4130 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);
4131 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);
4132 leaflist = r_shadow_buffer_leaflist;
4133 leafpvs = r_shadow_buffer_leafpvs;
4134 surfacelist = r_shadow_buffer_surfacelist;
4135 surfacesides = r_shadow_buffer_surfacesides;
4136 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4137 lighttrispvs = r_shadow_buffer_lighttrispvs;
4138 // if the reduced leaf bounds are offscreen, skip it
4139 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4150 surfacesides = NULL;
4151 shadowtrispvs = NULL;
4152 lighttrispvs = NULL;
4154 // check if light is illuminating any visible leafs
4157 for (i = 0;i < numleafs;i++)
4158 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4163 // set up a scissor rectangle for this light
4164 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4167 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4169 // make a list of lit entities and shadow casting entities
4170 numlightentities = 0;
4171 numlightentities_noselfshadow = 0;
4172 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4173 numshadowentities = 0;
4174 numshadowentities_noselfshadow = 0;
4175 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4177 // add dynamic entities that are lit by the light
4178 if (r_drawentities.integer)
4180 for (i = 0;i < r_refdef.scene.numentities;i++)
4183 entity_render_t *ent = r_refdef.scene.entities[i];
4185 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4187 // skip the object entirely if it is not within the valid
4188 // shadow-casting region (which includes the lit region)
4189 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4191 if (!(model = ent->model))
4193 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4195 // this entity wants to receive light, is visible, and is
4196 // inside the light box
4197 // TODO: check if the surfaces in the model can receive light
4198 // so now check if it's in a leaf seen by the light
4199 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))
4201 if (ent->flags & RENDER_NOSELFSHADOW)
4202 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4204 lightentities[numlightentities++] = ent;
4205 // since it is lit, it probably also casts a shadow...
4206 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4207 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4208 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4210 // note: exterior models without the RENDER_NOSELFSHADOW
4211 // flag still create a RENDER_NOSELFSHADOW shadow but
4212 // are lit normally, this means that they are
4213 // self-shadowing but do not shadow other
4214 // RENDER_NOSELFSHADOW entities such as the gun
4215 // (very weird, but keeps the player shadow off the gun)
4216 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4217 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4219 shadowentities[numshadowentities++] = ent;
4222 else if (ent->flags & RENDER_SHADOW)
4224 // this entity is not receiving light, but may still need to
4226 // TODO: check if the surfaces in the model can cast shadow
4227 // now check if it is in a leaf seen by the light
4228 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))
4230 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4231 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4232 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4234 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4235 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4237 shadowentities[numshadowentities++] = ent;
4243 // return if there's nothing at all to light
4244 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4247 // don't let sound skip if going slow
4248 if (r_refdef.scene.extraupdate)
4251 // make this the active rtlight for rendering purposes
4252 R_Shadow_RenderMode_ActiveLight(rtlight);
4253 // count this light in the r_speeds
4254 r_refdef.stats.lights++;
4256 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4258 // optionally draw visible shape of the shadow volumes
4259 // for performance analysis by level designers
4260 R_Shadow_RenderMode_VisibleShadowVolumes();
4262 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4263 for (i = 0;i < numshadowentities;i++)
4264 R_Shadow_DrawEntityShadow(shadowentities[i]);
4265 for (i = 0;i < numshadowentities_noselfshadow;i++)
4266 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4269 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4271 // optionally draw the illuminated areas
4272 // for performance analysis by level designers
4273 R_Shadow_RenderMode_VisibleLighting(false, false);
4275 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4276 for (i = 0;i < numlightentities;i++)
4277 R_Shadow_DrawEntityLight(lightentities[i]);
4278 for (i = 0;i < numlightentities_noselfshadow;i++)
4279 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4282 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4284 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4285 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4286 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4287 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4289 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4290 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4291 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4293 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
4299 int receivermask = 0;
4300 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4301 Matrix4x4_Abs(&radiustolight);
4303 r_shadow_shadowmaplod = 0;
4304 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4305 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4306 r_shadow_shadowmaplod = i;
4308 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
4309 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
4311 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4313 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4317 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4319 castermask = rtlight->static_shadowmap_casters;
4320 receivermask = rtlight->static_shadowmap_receivers;
4324 for(i = 0;i < numsurfaces;i++)
4326 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4327 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4328 castermask |= surfacesides[i];
4329 receivermask |= surfacesides[i];
4333 if (receivermask < 0x3F)
4335 for (i = 0;i < numlightentities;i++)
4336 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4337 if (receivermask < 0x3F)
4338 for(i = 0; i < numlightentities_noselfshadow;i++)
4339 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4342 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4346 for (i = 0;i < numshadowentities;i++)
4347 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4348 for (i = 0;i < numshadowentities_noselfshadow;i++)
4349 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4352 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4354 // render shadow casters into 6 sided depth texture
4355 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4357 R_Shadow_RenderMode_ShadowMap(side, true, size);
4358 if (! (castermask & (1 << side))) continue;
4360 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4361 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4362 R_Shadow_DrawEntityShadow(shadowentities[i]);
4365 if (numlightentities_noselfshadow)
4367 // render lighting using the depth texture as shadowmap
4368 // draw lighting in the unmasked areas
4369 R_Shadow_RenderMode_Lighting(false, false, true);
4370 for (i = 0;i < numlightentities_noselfshadow;i++)
4371 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4374 // render shadow casters into 6 sided depth texture
4375 if (numshadowentities_noselfshadow)
4377 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4379 R_Shadow_RenderMode_ShadowMap(side, false, size);
4380 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] & (1 << side))
4381 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4385 // render lighting using the depth texture as shadowmap
4386 // draw lighting in the unmasked areas
4387 R_Shadow_RenderMode_Lighting(false, false, true);
4388 // draw lighting in the unmasked areas
4390 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4391 for (i = 0;i < numlightentities;i++)
4392 R_Shadow_DrawEntityLight(lightentities[i]);
4394 else if (castshadows && vid.stencil)
4396 // draw stencil shadow volumes to mask off pixels that are in shadow
4397 // so that they won't receive lighting
4398 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4399 R_Shadow_ClearStencil();
4401 if (numsurfaces + numshadowentities)
4404 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4405 for (i = 0;i < numshadowentities;i++)
4406 R_Shadow_DrawEntityShadow(shadowentities[i]);
4409 if (numlightentities_noselfshadow)
4411 // draw lighting in the unmasked areas
4412 R_Shadow_RenderMode_Lighting(true, false, false);
4413 for (i = 0;i < numlightentities_noselfshadow;i++)
4414 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4416 // optionally draw the illuminated areas
4417 // for performance analysis by level designers
4418 if (r_showlighting.integer && r_refdef.view.showdebug)
4420 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4421 for (i = 0;i < numlightentities_noselfshadow;i++)
4422 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4424 for (i = 0;i < numshadowentities_noselfshadow;i++)
4425 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4428 if (numsurfaces + numlightentities)
4430 // draw lighting in the unmasked areas
4431 R_Shadow_RenderMode_Lighting(true, false, false);
4433 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4434 for (i = 0;i < numlightentities;i++)
4435 R_Shadow_DrawEntityLight(lightentities[i]);
4440 // draw lighting in the unmasked areas
4441 R_Shadow_RenderMode_Lighting(false, false, false);
4443 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4444 for (i = 0;i < numlightentities;i++)
4445 R_Shadow_DrawEntityLight(lightentities[i]);
4446 for (i = 0;i < numlightentities_noselfshadow;i++)
4447 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4451 void R_Shadow_DrawLightSprites(void);
4452 void R_ShadowVolumeLighting(qboolean visible)
4461 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, gl_max_size.integer / 4) ||
4462 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer && r_glsl.integer && vid.support.arb_fragment_shader && vid.support.ext_framebuffer_object) ||
4463 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4464 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4465 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4466 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4467 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4468 R_Shadow_FreeShadowMaps();
4470 if (r_editlights.integer)
4471 R_Shadow_DrawLightSprites();
4473 R_Shadow_RenderMode_Begin();
4475 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4476 if (r_shadow_debuglight.integer >= 0)
4478 lightindex = r_shadow_debuglight.integer;
4479 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4480 if (light && (light->flags & flag))
4481 R_DrawRTLight(&light->rtlight, visible);
4485 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4486 for (lightindex = 0;lightindex < range;lightindex++)
4488 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4489 if (light && (light->flags & flag))
4490 R_DrawRTLight(&light->rtlight, visible);
4493 if (r_refdef.scene.rtdlight)
4495 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4496 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4498 else if(gl_flashblend.integer)
4500 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4502 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4503 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4504 VectorScale(rtlight->color, f, rtlight->currentcolor);
4508 R_Shadow_RenderMode_End();
4511 extern const float r_screenvertex3f[12];
4512 extern void R_SetupView(qboolean allowwaterclippingplane);
4513 extern void R_ResetViewRendering3D(void);
4514 extern void R_ResetViewRendering2D(void);
4515 extern cvar_t r_shadows;
4516 extern cvar_t r_shadows_darken;
4517 extern cvar_t r_shadows_drawafterrtlighting;
4518 extern cvar_t r_shadows_castfrombmodels;
4519 extern cvar_t r_shadows_throwdistance;
4520 extern cvar_t r_shadows_throwdirection;
4521 void R_DrawModelShadows(void)
4524 float relativethrowdistance;
4525 entity_render_t *ent;
4526 vec3_t relativelightorigin;
4527 vec3_t relativelightdirection;
4528 vec3_t relativeshadowmins, relativeshadowmaxs;
4529 vec3_t tmp, shadowdir;
4531 if (!r_drawentities.integer || !vid.stencil)
4535 R_ResetViewRendering3D();
4536 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4537 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4538 R_Shadow_RenderMode_Begin();
4539 R_Shadow_RenderMode_ActiveLight(NULL);
4540 r_shadow_lightscissor[0] = r_refdef.view.x;
4541 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4542 r_shadow_lightscissor[2] = r_refdef.view.width;
4543 r_shadow_lightscissor[3] = r_refdef.view.height;
4544 R_Shadow_RenderMode_StencilShadowVolumes(false);
4547 if (r_shadows.integer == 2)
4549 Math_atov(r_shadows_throwdirection.string, shadowdir);
4550 VectorNormalize(shadowdir);
4553 R_Shadow_ClearStencil();
4555 for (i = 0;i < r_refdef.scene.numentities;i++)
4557 ent = r_refdef.scene.entities[i];
4559 // cast shadows from anything of the map (submodels are optional)
4560 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4562 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4563 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4564 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4565 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4566 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4569 if(ent->entitynumber != 0)
4571 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4572 int entnum, entnum2, recursion;
4573 entnum = entnum2 = ent->entitynumber;
4574 for(recursion = 32; recursion > 0; --recursion)
4576 entnum2 = cl.entities[entnum].state_current.tagentity;
4577 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4582 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4584 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4585 // transform into modelspace of OUR entity
4586 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4587 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4590 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4593 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4596 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4597 RSurf_ActiveModelEntity(ent, false, false);
4598 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4599 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4603 // not really the right mode, but this will disable any silly stencil features
4604 R_Shadow_RenderMode_End();
4606 // set up ortho view for rendering this pass
4607 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4608 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4609 //GL_ScissorTest(true);
4610 //R_Mesh_Matrix(&identitymatrix);
4611 //R_Mesh_ResetTextureState();
4612 R_ResetViewRendering2D();
4613 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4614 R_Mesh_ColorPointer(NULL, 0, 0);
4615 R_SetupGenericShader(false);
4617 // set up a darkening blend on shadowed areas
4618 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4619 //GL_DepthRange(0, 1);
4620 //GL_DepthTest(false);
4621 //GL_DepthMask(false);
4622 //GL_PolygonOffset(0, 0);CHECKGLERROR
4623 GL_Color(0, 0, 0, r_shadows_darken.value);
4624 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4625 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4626 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4627 qglStencilMask(~0);CHECKGLERROR
4628 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4629 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4631 // apply the blend to the shadowed areas
4632 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4634 // restore the viewport
4635 R_SetViewport(&r_refdef.view.viewport);
4637 // restore other state to normal
4638 //R_Shadow_RenderMode_End();
4641 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4644 vec3_t centerorigin;
4646 // if it's too close, skip it
4647 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4649 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4652 if (usequery && r_numqueries + 2 <= r_maxqueries)
4654 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4655 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4656 // we count potential samples in the middle of the screen, we count actual samples at the light location, this allows counting potential samples of off-screen lights
4657 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4660 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4661 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4662 qglDepthFunc(GL_ALWAYS);
4663 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4664 R_Mesh_VertexPointer(vertex3f, 0, 0);
4665 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4666 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4667 qglDepthFunc(GL_LEQUAL);
4668 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4669 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4670 R_Mesh_VertexPointer(vertex3f, 0, 0);
4671 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4672 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4675 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4678 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4680 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4683 GLint allpixels = 0, visiblepixels = 0;
4684 // now we have to check the query result
4685 if (rtlight->corona_queryindex_visiblepixels)
4688 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4689 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4691 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4692 if (visiblepixels < 1 || allpixels < 1)
4694 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4695 cscale *= rtlight->corona_visibility;
4699 // FIXME: these traces should scan all render entities instead of cl.world
4700 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4703 VectorScale(rtlight->currentcolor, cscale, color);
4704 if (VectorLength(color) > (1.0f / 256.0f))
4707 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4710 VectorNegate(color, color);
4711 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4713 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4714 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, RENDER_NODEPTHTEST, 0, color[0], color[1], color[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4715 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4717 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4721 void R_DrawCoronas(void)
4729 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4731 if (r_waterstate.renderingscene)
4733 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4734 R_Mesh_Matrix(&identitymatrix);
4736 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4738 // check occlusion of coronas
4739 // use GL_ARB_occlusion_query if available
4740 // otherwise use raytraces
4742 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4745 GL_ColorMask(0,0,0,0);
4746 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4747 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4750 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4751 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4753 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4756 RSurf_ActiveWorldEntity();
4757 GL_BlendFunc(GL_ONE, GL_ZERO);
4758 GL_CullFace(GL_NONE);
4759 GL_DepthMask(false);
4760 GL_DepthRange(0, 1);
4761 GL_PolygonOffset(0, 0);
4763 R_Mesh_ColorPointer(NULL, 0, 0);
4764 R_Mesh_ResetTextureState();
4765 R_SetupGenericShader(false);
4767 for (lightindex = 0;lightindex < range;lightindex++)
4769 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4772 rtlight = &light->rtlight;
4773 rtlight->corona_visibility = 0;
4774 rtlight->corona_queryindex_visiblepixels = 0;
4775 rtlight->corona_queryindex_allpixels = 0;
4776 if (!(rtlight->flags & flag))
4778 if (rtlight->corona <= 0)
4780 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4782 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4784 for (i = 0;i < r_refdef.scene.numlights;i++)
4786 rtlight = r_refdef.scene.lights[i];
4787 rtlight->corona_visibility = 0;
4788 rtlight->corona_queryindex_visiblepixels = 0;
4789 rtlight->corona_queryindex_allpixels = 0;
4790 if (!(rtlight->flags & flag))
4792 if (rtlight->corona <= 0)
4794 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4797 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4799 // now draw the coronas using the query data for intensity info
4800 for (lightindex = 0;lightindex < range;lightindex++)
4802 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4805 rtlight = &light->rtlight;
4806 if (rtlight->corona_visibility <= 0)
4808 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4810 for (i = 0;i < r_refdef.scene.numlights;i++)
4812 rtlight = r_refdef.scene.lights[i];
4813 if (rtlight->corona_visibility <= 0)
4815 if (gl_flashblend.integer)
4816 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4818 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4824 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4825 typedef struct suffixinfo_s
4828 qboolean flipx, flipy, flipdiagonal;
4831 static suffixinfo_t suffix[3][6] =
4834 {"px", false, false, false},
4835 {"nx", false, false, false},
4836 {"py", false, false, false},
4837 {"ny", false, false, false},
4838 {"pz", false, false, false},
4839 {"nz", false, false, false}
4842 {"posx", false, false, false},
4843 {"negx", false, false, false},
4844 {"posy", false, false, false},
4845 {"negy", false, false, false},
4846 {"posz", false, false, false},
4847 {"negz", false, false, false}
4850 {"rt", true, false, true},
4851 {"lf", false, true, true},
4852 {"ft", true, true, false},
4853 {"bk", false, false, false},
4854 {"up", true, false, true},
4855 {"dn", true, false, true}
4859 static int componentorder[4] = {0, 1, 2, 3};
4861 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4863 int i, j, cubemapsize;
4864 unsigned char *cubemappixels, *image_buffer;
4865 rtexture_t *cubemaptexture;
4867 // must start 0 so the first loadimagepixels has no requested width/height
4869 cubemappixels = NULL;
4870 cubemaptexture = NULL;
4871 // keep trying different suffix groups (posx, px, rt) until one loads
4872 for (j = 0;j < 3 && !cubemappixels;j++)
4874 // load the 6 images in the suffix group
4875 for (i = 0;i < 6;i++)
4877 // generate an image name based on the base and and suffix
4878 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4880 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4882 // an image loaded, make sure width and height are equal
4883 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4885 // if this is the first image to load successfully, allocate the cubemap memory
4886 if (!cubemappixels && image_width >= 1)
4888 cubemapsize = image_width;
4889 // note this clears to black, so unavailable sides are black
4890 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4892 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4894 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);
4897 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4899 Mem_Free(image_buffer);
4903 // if a cubemap loaded, upload it
4906 if (developer_loading.integer)
4907 Con_Printf("loading cubemap \"%s\"\n", basename);
4909 if (!r_shadow_filters_texturepool)
4910 r_shadow_filters_texturepool = R_AllocTexturePool();
4911 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4912 Mem_Free(cubemappixels);
4916 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4917 if (developer_loading.integer)
4919 Con_Printf("(tried tried images ");
4920 for (j = 0;j < 3;j++)
4921 for (i = 0;i < 6;i++)
4922 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4923 Con_Print(" and was unable to find any of them).\n");
4926 return cubemaptexture;
4929 rtexture_t *R_Shadow_Cubemap(const char *basename)
4932 for (i = 0;i < numcubemaps;i++)
4933 if (!strcasecmp(cubemaps[i].basename, basename))
4934 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4935 if (i >= MAX_CUBEMAPS)
4936 return r_texture_whitecube;
4938 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4939 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4940 return cubemaps[i].texture;
4943 void R_Shadow_FreeCubemaps(void)
4946 for (i = 0;i < numcubemaps;i++)
4948 if (developer_loading.integer)
4949 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4950 if (cubemaps[i].texture)
4951 R_FreeTexture(cubemaps[i].texture);
4955 R_FreeTexturePool(&r_shadow_filters_texturepool);
4958 dlight_t *R_Shadow_NewWorldLight(void)
4960 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4963 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)
4966 // validate parameters
4967 if (style < 0 || style >= MAX_LIGHTSTYLES)
4969 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4975 // copy to light properties
4976 VectorCopy(origin, light->origin);
4977 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4978 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4979 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4981 light->color[0] = max(color[0], 0);
4982 light->color[1] = max(color[1], 0);
4983 light->color[2] = max(color[2], 0);
4985 light->color[0] = color[0];
4986 light->color[1] = color[1];
4987 light->color[2] = color[2];
4988 light->radius = max(radius, 0);
4989 light->style = style;
4990 light->shadow = shadowenable;
4991 light->corona = corona;
4992 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4993 light->coronasizescale = coronasizescale;
4994 light->ambientscale = ambientscale;
4995 light->diffusescale = diffusescale;
4996 light->specularscale = specularscale;
4997 light->flags = flags;
4999 // update renderable light data
5000 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5001 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);
5004 void R_Shadow_FreeWorldLight(dlight_t *light)
5006 if (r_shadow_selectedlight == light)
5007 r_shadow_selectedlight = NULL;
5008 R_RTLight_Uncompile(&light->rtlight);
5009 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5012 void R_Shadow_ClearWorldLights(void)
5016 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5017 for (lightindex = 0;lightindex < range;lightindex++)
5019 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5021 R_Shadow_FreeWorldLight(light);
5023 r_shadow_selectedlight = NULL;
5024 R_Shadow_FreeCubemaps();
5027 void R_Shadow_SelectLight(dlight_t *light)
5029 if (r_shadow_selectedlight)
5030 r_shadow_selectedlight->selected = false;
5031 r_shadow_selectedlight = light;
5032 if (r_shadow_selectedlight)
5033 r_shadow_selectedlight->selected = true;
5036 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5038 // this is never batched (there can be only one)
5040 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5041 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5042 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5045 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5050 skinframe_t *skinframe;
5053 // this is never batched (due to the ent parameter changing every time)
5054 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5055 const dlight_t *light = (dlight_t *)ent;
5058 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5061 VectorScale(light->color, intensity, spritecolor);
5062 if (VectorLength(spritecolor) < 0.1732f)
5063 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5064 if (VectorLength(spritecolor) > 1.0f)
5065 VectorNormalize(spritecolor);
5067 // draw light sprite
5068 if (light->cubemapname[0] && !light->shadow)
5069 skinframe = r_editlights_sprcubemapnoshadowlight;
5070 else if (light->cubemapname[0])
5071 skinframe = r_editlights_sprcubemaplight;
5072 else if (!light->shadow)
5073 skinframe = r_editlights_sprnoshadowlight;
5075 skinframe = r_editlights_sprlight;
5077 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, spritecolor[0], spritecolor[1], spritecolor[2], 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5078 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5080 // draw selection sprite if light is selected
5081 if (light->selected)
5083 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5084 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
5085 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5089 void R_Shadow_DrawLightSprites(void)
5093 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5094 for (lightindex = 0;lightindex < range;lightindex++)
5096 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5098 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5100 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5103 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5108 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5109 if (lightindex >= range)
5111 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5114 rtlight = &light->rtlight;
5115 //if (!(rtlight->flags & flag))
5117 VectorCopy(rtlight->shadoworigin, origin);
5118 *radius = rtlight->radius;
5119 VectorCopy(rtlight->color, color);
5123 void R_Shadow_SelectLightInView(void)
5125 float bestrating, rating, temp[3];
5129 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5132 for (lightindex = 0;lightindex < range;lightindex++)
5134 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5137 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5138 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5141 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5142 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5144 bestrating = rating;
5149 R_Shadow_SelectLight(best);
5152 void R_Shadow_LoadWorldLights(void)
5154 int n, a, style, shadow, flags;
5155 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5156 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5157 if (cl.worldmodel == NULL)
5159 Con_Print("No map loaded.\n");
5162 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5163 strlcat (name, ".rtlights", sizeof (name));
5164 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5174 for (;COM_Parse(t, true) && strcmp(
5175 if (COM_Parse(t, true))
5177 if (com_token[0] == '!')
5180 origin[0] = atof(com_token+1);
5183 origin[0] = atof(com_token);
5188 while (*s && *s != '\n' && *s != '\r')
5194 // check for modifier flags
5201 #if _MSC_VER >= 1400
5202 #define sscanf sscanf_s
5204 cubemapname[sizeof(cubemapname)-1] = 0;
5205 #if MAX_QPATH != 128
5206 #error update this code if MAX_QPATH changes
5208 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
5209 #if _MSC_VER >= 1400
5210 , sizeof(cubemapname)
5212 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5215 flags = LIGHTFLAG_REALTIMEMODE;
5223 coronasizescale = 0.25f;
5225 VectorClear(angles);
5228 if (a < 9 || !strcmp(cubemapname, "\"\""))
5230 // remove quotes on cubemapname
5231 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5234 namelen = strlen(cubemapname) - 2;
5235 memmove(cubemapname, cubemapname + 1, namelen);
5236 cubemapname[namelen] = '\0';
5240 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);
5243 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5251 Con_Printf("invalid rtlights file \"%s\"\n", name);
5252 Mem_Free(lightsstring);
5256 void R_Shadow_SaveWorldLights(void)
5260 size_t bufchars, bufmaxchars;
5262 char name[MAX_QPATH];
5263 char line[MAX_INPUTLINE];
5264 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5265 // I hate lines which are 3 times my screen size :( --blub
5268 if (cl.worldmodel == NULL)
5270 Con_Print("No map loaded.\n");
5273 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5274 strlcat (name, ".rtlights", sizeof (name));
5275 bufchars = bufmaxchars = 0;
5277 for (lightindex = 0;lightindex < range;lightindex++)
5279 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5282 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5283 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);
5284 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5285 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]);
5287 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);
5288 if (bufchars + strlen(line) > bufmaxchars)
5290 bufmaxchars = bufchars + strlen(line) + 2048;
5292 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5296 memcpy(buf, oldbuf, bufchars);
5302 memcpy(buf + bufchars, line, strlen(line));
5303 bufchars += strlen(line);
5307 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5312 void R_Shadow_LoadLightsFile(void)
5315 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5316 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5317 if (cl.worldmodel == NULL)
5319 Con_Print("No map loaded.\n");
5322 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5323 strlcat (name, ".lights", sizeof (name));
5324 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5332 while (*s && *s != '\n' && *s != '\r')
5338 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);
5342 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);
5345 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5346 radius = bound(15, radius, 4096);
5347 VectorScale(color, (2.0f / (8388608.0f)), color);
5348 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5356 Con_Printf("invalid lights file \"%s\"\n", name);
5357 Mem_Free(lightsstring);
5361 // tyrlite/hmap2 light types in the delay field
5362 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5364 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5366 int entnum, style, islight, skin, pflags, effects, type, n;
5369 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5370 char key[256], value[MAX_INPUTLINE];
5372 if (cl.worldmodel == NULL)
5374 Con_Print("No map loaded.\n");
5377 // try to load a .ent file first
5378 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5379 strlcat (key, ".ent", sizeof (key));
5380 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5381 // and if that is not found, fall back to the bsp file entity string
5383 data = cl.worldmodel->brush.entities;
5386 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5388 type = LIGHTTYPE_MINUSX;
5389 origin[0] = origin[1] = origin[2] = 0;
5390 originhack[0] = originhack[1] = originhack[2] = 0;
5391 angles[0] = angles[1] = angles[2] = 0;
5392 color[0] = color[1] = color[2] = 1;
5393 light[0] = light[1] = light[2] = 1;light[3] = 300;
5394 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5404 if (!COM_ParseToken_Simple(&data, false, false))
5406 if (com_token[0] == '}')
5407 break; // end of entity
5408 if (com_token[0] == '_')
5409 strlcpy(key, com_token + 1, sizeof(key));
5411 strlcpy(key, com_token, sizeof(key));
5412 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5413 key[strlen(key)-1] = 0;
5414 if (!COM_ParseToken_Simple(&data, false, false))
5416 strlcpy(value, com_token, sizeof(value));
5418 // now that we have the key pair worked out...
5419 if (!strcmp("light", key))
5421 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5425 light[0] = vec[0] * (1.0f / 256.0f);
5426 light[1] = vec[0] * (1.0f / 256.0f);
5427 light[2] = vec[0] * (1.0f / 256.0f);
5433 light[0] = vec[0] * (1.0f / 255.0f);
5434 light[1] = vec[1] * (1.0f / 255.0f);
5435 light[2] = vec[2] * (1.0f / 255.0f);
5439 else if (!strcmp("delay", key))
5441 else if (!strcmp("origin", key))
5442 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5443 else if (!strcmp("angle", key))
5444 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5445 else if (!strcmp("angles", key))
5446 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5447 else if (!strcmp("color", key))
5448 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5449 else if (!strcmp("wait", key))
5450 fadescale = atof(value);
5451 else if (!strcmp("classname", key))
5453 if (!strncmp(value, "light", 5))
5456 if (!strcmp(value, "light_fluoro"))
5461 overridecolor[0] = 1;
5462 overridecolor[1] = 1;
5463 overridecolor[2] = 1;
5465 if (!strcmp(value, "light_fluorospark"))
5470 overridecolor[0] = 1;
5471 overridecolor[1] = 1;
5472 overridecolor[2] = 1;
5474 if (!strcmp(value, "light_globe"))
5479 overridecolor[0] = 1;
5480 overridecolor[1] = 0.8;
5481 overridecolor[2] = 0.4;
5483 if (!strcmp(value, "light_flame_large_yellow"))
5488 overridecolor[0] = 1;
5489 overridecolor[1] = 0.5;
5490 overridecolor[2] = 0.1;
5492 if (!strcmp(value, "light_flame_small_yellow"))
5497 overridecolor[0] = 1;
5498 overridecolor[1] = 0.5;
5499 overridecolor[2] = 0.1;
5501 if (!strcmp(value, "light_torch_small_white"))
5506 overridecolor[0] = 1;
5507 overridecolor[1] = 0.5;
5508 overridecolor[2] = 0.1;
5510 if (!strcmp(value, "light_torch_small_walltorch"))
5515 overridecolor[0] = 1;
5516 overridecolor[1] = 0.5;
5517 overridecolor[2] = 0.1;
5521 else if (!strcmp("style", key))
5522 style = atoi(value);
5523 else if (!strcmp("skin", key))
5524 skin = (int)atof(value);
5525 else if (!strcmp("pflags", key))
5526 pflags = (int)atof(value);
5527 else if (!strcmp("effects", key))
5528 effects = (int)atof(value);
5529 else if (cl.worldmodel->type == mod_brushq3)
5531 if (!strcmp("scale", key))
5532 lightscale = atof(value);
5533 if (!strcmp("fade", key))
5534 fadescale = atof(value);
5539 if (lightscale <= 0)
5543 if (color[0] == color[1] && color[0] == color[2])
5545 color[0] *= overridecolor[0];
5546 color[1] *= overridecolor[1];
5547 color[2] *= overridecolor[2];
5549 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5550 color[0] = color[0] * light[0];
5551 color[1] = color[1] * light[1];
5552 color[2] = color[2] * light[2];
5555 case LIGHTTYPE_MINUSX:
5557 case LIGHTTYPE_RECIPX:
5559 VectorScale(color, (1.0f / 16.0f), color);
5561 case LIGHTTYPE_RECIPXX:
5563 VectorScale(color, (1.0f / 16.0f), color);
5566 case LIGHTTYPE_NONE:
5570 case LIGHTTYPE_MINUSXX:
5573 VectorAdd(origin, originhack, origin);
5575 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);
5578 Mem_Free(entfiledata);
5582 void R_Shadow_SetCursorLocationForView(void)
5585 vec3_t dest, endpos;
5587 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5588 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5589 if (trace.fraction < 1)
5591 dist = trace.fraction * r_editlights_cursordistance.value;
5592 push = r_editlights_cursorpushback.value;
5596 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5597 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5601 VectorClear( endpos );
5603 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5604 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5605 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5608 void R_Shadow_UpdateWorldLightSelection(void)
5610 if (r_editlights.integer)
5612 R_Shadow_SetCursorLocationForView();
5613 R_Shadow_SelectLightInView();
5616 R_Shadow_SelectLight(NULL);
5619 void R_Shadow_EditLights_Clear_f(void)
5621 R_Shadow_ClearWorldLights();
5624 void R_Shadow_EditLights_Reload_f(void)
5628 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5629 R_Shadow_ClearWorldLights();
5630 R_Shadow_LoadWorldLights();
5631 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5633 R_Shadow_LoadLightsFile();
5634 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5635 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5639 void R_Shadow_EditLights_Save_f(void)
5643 R_Shadow_SaveWorldLights();
5646 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5648 R_Shadow_ClearWorldLights();
5649 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5652 void R_Shadow_EditLights_ImportLightsFile_f(void)
5654 R_Shadow_ClearWorldLights();
5655 R_Shadow_LoadLightsFile();
5658 void R_Shadow_EditLights_Spawn_f(void)
5661 if (!r_editlights.integer)
5663 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5666 if (Cmd_Argc() != 1)
5668 Con_Print("r_editlights_spawn does not take parameters\n");
5671 color[0] = color[1] = color[2] = 1;
5672 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5675 void R_Shadow_EditLights_Edit_f(void)
5677 vec3_t origin, angles, color;
5678 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5679 int style, shadows, flags, normalmode, realtimemode;
5680 char cubemapname[MAX_INPUTLINE];
5681 if (!r_editlights.integer)
5683 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5686 if (!r_shadow_selectedlight)
5688 Con_Print("No selected light.\n");
5691 VectorCopy(r_shadow_selectedlight->origin, origin);
5692 VectorCopy(r_shadow_selectedlight->angles, angles);
5693 VectorCopy(r_shadow_selectedlight->color, color);
5694 radius = r_shadow_selectedlight->radius;
5695 style = r_shadow_selectedlight->style;
5696 if (r_shadow_selectedlight->cubemapname)
5697 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5700 shadows = r_shadow_selectedlight->shadow;
5701 corona = r_shadow_selectedlight->corona;
5702 coronasizescale = r_shadow_selectedlight->coronasizescale;
5703 ambientscale = r_shadow_selectedlight->ambientscale;
5704 diffusescale = r_shadow_selectedlight->diffusescale;
5705 specularscale = r_shadow_selectedlight->specularscale;
5706 flags = r_shadow_selectedlight->flags;
5707 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5708 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5709 if (!strcmp(Cmd_Argv(1), "origin"))
5711 if (Cmd_Argc() != 5)
5713 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5716 origin[0] = atof(Cmd_Argv(2));
5717 origin[1] = atof(Cmd_Argv(3));
5718 origin[2] = atof(Cmd_Argv(4));
5720 else if (!strcmp(Cmd_Argv(1), "originx"))
5722 if (Cmd_Argc() != 3)
5724 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5727 origin[0] = atof(Cmd_Argv(2));
5729 else if (!strcmp(Cmd_Argv(1), "originy"))
5731 if (Cmd_Argc() != 3)
5733 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5736 origin[1] = atof(Cmd_Argv(2));
5738 else if (!strcmp(Cmd_Argv(1), "originz"))
5740 if (Cmd_Argc() != 3)
5742 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5745 origin[2] = atof(Cmd_Argv(2));
5747 else if (!strcmp(Cmd_Argv(1), "move"))
5749 if (Cmd_Argc() != 5)
5751 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5754 origin[0] += atof(Cmd_Argv(2));
5755 origin[1] += atof(Cmd_Argv(3));
5756 origin[2] += atof(Cmd_Argv(4));
5758 else if (!strcmp(Cmd_Argv(1), "movex"))
5760 if (Cmd_Argc() != 3)
5762 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5765 origin[0] += atof(Cmd_Argv(2));
5767 else if (!strcmp(Cmd_Argv(1), "movey"))
5769 if (Cmd_Argc() != 3)
5771 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5774 origin[1] += atof(Cmd_Argv(2));
5776 else if (!strcmp(Cmd_Argv(1), "movez"))
5778 if (Cmd_Argc() != 3)
5780 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5783 origin[2] += atof(Cmd_Argv(2));
5785 else if (!strcmp(Cmd_Argv(1), "angles"))
5787 if (Cmd_Argc() != 5)
5789 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5792 angles[0] = atof(Cmd_Argv(2));
5793 angles[1] = atof(Cmd_Argv(3));
5794 angles[2] = atof(Cmd_Argv(4));
5796 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5798 if (Cmd_Argc() != 3)
5800 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5803 angles[0] = atof(Cmd_Argv(2));
5805 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5807 if (Cmd_Argc() != 3)
5809 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5812 angles[1] = atof(Cmd_Argv(2));
5814 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5816 if (Cmd_Argc() != 3)
5818 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5821 angles[2] = atof(Cmd_Argv(2));
5823 else if (!strcmp(Cmd_Argv(1), "color"))
5825 if (Cmd_Argc() != 5)
5827 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5830 color[0] = atof(Cmd_Argv(2));
5831 color[1] = atof(Cmd_Argv(3));
5832 color[2] = atof(Cmd_Argv(4));
5834 else if (!strcmp(Cmd_Argv(1), "radius"))
5836 if (Cmd_Argc() != 3)
5838 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5841 radius = atof(Cmd_Argv(2));
5843 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5845 if (Cmd_Argc() == 3)
5847 double scale = atof(Cmd_Argv(2));
5854 if (Cmd_Argc() != 5)
5856 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5859 color[0] *= atof(Cmd_Argv(2));
5860 color[1] *= atof(Cmd_Argv(3));
5861 color[2] *= atof(Cmd_Argv(4));
5864 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5866 if (Cmd_Argc() != 3)
5868 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5871 radius *= atof(Cmd_Argv(2));
5873 else if (!strcmp(Cmd_Argv(1), "style"))
5875 if (Cmd_Argc() != 3)
5877 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5880 style = atoi(Cmd_Argv(2));
5882 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5889 if (Cmd_Argc() == 3)
5890 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5894 else if (!strcmp(Cmd_Argv(1), "shadows"))
5896 if (Cmd_Argc() != 3)
5898 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5901 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5903 else if (!strcmp(Cmd_Argv(1), "corona"))
5905 if (Cmd_Argc() != 3)
5907 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5910 corona = atof(Cmd_Argv(2));
5912 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5914 if (Cmd_Argc() != 3)
5916 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5919 coronasizescale = atof(Cmd_Argv(2));
5921 else if (!strcmp(Cmd_Argv(1), "ambient"))
5923 if (Cmd_Argc() != 3)
5925 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5928 ambientscale = atof(Cmd_Argv(2));
5930 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5932 if (Cmd_Argc() != 3)
5934 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5937 diffusescale = atof(Cmd_Argv(2));
5939 else if (!strcmp(Cmd_Argv(1), "specular"))
5941 if (Cmd_Argc() != 3)
5943 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5946 specularscale = atof(Cmd_Argv(2));
5948 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5950 if (Cmd_Argc() != 3)
5952 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5955 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5957 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5959 if (Cmd_Argc() != 3)
5961 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5964 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5968 Con_Print("usage: r_editlights_edit [property] [value]\n");
5969 Con_Print("Selected light's properties:\n");
5970 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5971 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5972 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5973 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5974 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5975 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5976 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5977 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5978 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5979 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5980 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5981 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5982 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5983 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5986 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5987 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5990 void R_Shadow_EditLights_EditAll_f(void)
5996 if (!r_editlights.integer)
5998 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6002 // EditLights doesn't seem to have a "remove" command or something so:
6003 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6004 for (lightindex = 0;lightindex < range;lightindex++)
6006 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6009 R_Shadow_SelectLight(light);
6010 R_Shadow_EditLights_Edit_f();
6014 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6016 int lightnumber, lightcount;
6017 size_t lightindex, range;
6021 if (!r_editlights.integer)
6023 x = vid_conwidth.value - 240;
6025 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6028 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6029 for (lightindex = 0;lightindex < range;lightindex++)
6031 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6034 if (light == r_shadow_selectedlight)
6035 lightnumber = lightindex;
6038 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;
6039 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;
6041 if (r_shadow_selectedlight == NULL)
6043 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;
6044 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;
6045 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;
6046 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;
6047 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;
6048 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;
6049 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;
6050 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;
6051 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;
6052 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;
6053 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;
6054 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;
6055 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;
6056 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;
6057 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;
6060 void R_Shadow_EditLights_ToggleShadow_f(void)
6062 if (!r_editlights.integer)
6064 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6067 if (!r_shadow_selectedlight)
6069 Con_Print("No selected light.\n");
6072 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);
6075 void R_Shadow_EditLights_ToggleCorona_f(void)
6077 if (!r_editlights.integer)
6079 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6082 if (!r_shadow_selectedlight)
6084 Con_Print("No selected light.\n");
6087 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);
6090 void R_Shadow_EditLights_Remove_f(void)
6092 if (!r_editlights.integer)
6094 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6097 if (!r_shadow_selectedlight)
6099 Con_Print("No selected light.\n");
6102 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6103 r_shadow_selectedlight = NULL;
6106 void R_Shadow_EditLights_Help_f(void)
6109 "Documentation on r_editlights system:\n"
6111 "r_editlights : enable/disable editing mode\n"
6112 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6113 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6114 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6115 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6116 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6118 "r_editlights_help : this help\n"
6119 "r_editlights_clear : remove all lights\n"
6120 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6121 "r_editlights_save : save to .rtlights file\n"
6122 "r_editlights_spawn : create a light with default settings\n"
6123 "r_editlights_edit command : edit selected light - more documentation below\n"
6124 "r_editlights_remove : remove selected light\n"
6125 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6126 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6127 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6129 "origin x y z : set light location\n"
6130 "originx x: set x component of light location\n"
6131 "originy y: set y component of light location\n"
6132 "originz z: set z component of light location\n"
6133 "move x y z : adjust light location\n"
6134 "movex x: adjust x component of light location\n"
6135 "movey y: adjust y component of light location\n"
6136 "movez z: adjust z component of light location\n"
6137 "angles x y z : set light angles\n"
6138 "anglesx x: set x component of light angles\n"
6139 "anglesy y: set y component of light angles\n"
6140 "anglesz z: set z component of light angles\n"
6141 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6142 "radius radius : set radius (size) of light\n"
6143 "colorscale grey : multiply color of light (1 does nothing)\n"
6144 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6145 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6146 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6147 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6148 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6149 "shadows 1/0 : turn on/off shadows\n"
6150 "corona n : set corona intensity\n"
6151 "coronasize n : set corona size (0-1)\n"
6152 "ambient n : set ambient intensity (0-1)\n"
6153 "diffuse n : set diffuse intensity (0-1)\n"
6154 "specular n : set specular intensity (0-1)\n"
6155 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6156 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6157 "<nothing> : print light properties to console\n"
6161 void R_Shadow_EditLights_CopyInfo_f(void)
6163 if (!r_editlights.integer)
6165 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6168 if (!r_shadow_selectedlight)
6170 Con_Print("No selected light.\n");
6173 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6174 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6175 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6176 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6177 if (r_shadow_selectedlight->cubemapname)
6178 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6180 r_shadow_bufferlight.cubemapname[0] = 0;
6181 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6182 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6183 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6184 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6185 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6186 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6187 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6190 void R_Shadow_EditLights_PasteInfo_f(void)
6192 if (!r_editlights.integer)
6194 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6197 if (!r_shadow_selectedlight)
6199 Con_Print("No selected light.\n");
6202 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);
6205 void R_Shadow_EditLights_Init(void)
6207 Cvar_RegisterVariable(&r_editlights);
6208 Cvar_RegisterVariable(&r_editlights_cursordistance);
6209 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6210 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6211 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6212 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6213 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6214 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6215 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)");
6216 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6217 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6218 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6219 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)");
6220 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6221 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6222 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6223 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6224 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6225 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6226 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)");
6232 =============================================================================
6236 =============================================================================
6239 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6241 VectorClear(diffusecolor);
6242 VectorClear(diffusenormal);
6244 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6246 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6247 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6250 VectorSet(ambientcolor, 1, 1, 1);
6257 for (i = 0;i < r_refdef.scene.numlights;i++)
6259 light = r_refdef.scene.lights[i];
6260 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6261 f = 1 - VectorLength2(v);
6262 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6263 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);