]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
d4c4570a740bfaa10cab122a9ab84f10580a7018
[xonotic/darkplaces.git] / r_shadow.c
1
2 /*
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)
9
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.
15
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).
22
23 Patent warning:
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).
29
30
31
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).
38
39
40
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
46 in some ideal cases).
47
48
49
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.
60
61
62
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.
69
70
71
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.
80
81
82
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
89 texturing).
90
91
92
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).
96
97
98
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.
103
104
105
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
114 this however).
115
116
117
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
127 other areas).
128
129
130
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.
135 */
136
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
140 #include "portals.h"
141 #include "image.h"
142 #include "dpsoftrast.h"
143
144 #ifdef SUPPORTD3D
145 #include <d3d9.h>
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
147 #endif
148
149 extern void R_Shadow_EditLights_Init(void);
150
151 typedef enum r_shadow_rendermode_e
152 {
153         R_SHADOW_RENDERMODE_NONE,
154         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160         R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161         R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162         R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163         R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164         R_SHADOW_RENDERMODE_LIGHT_GLSL,
165         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167         R_SHADOW_RENDERMODE_SHADOWMAP2D
168 }
169 r_shadow_rendermode_t;
170
171 typedef enum r_shadow_shadowmode_e
172 {
173     R_SHADOW_SHADOWMODE_STENCIL,
174     R_SHADOW_SHADOWMODE_SHADOWMAP2D
175 }
176 r_shadow_shadowmode_t;
177
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
187 #if 0
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
190 #endif
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
204
205 int maxshadowtriangles;
206 int *shadowelements;
207
208 int maxshadowvertices;
209 float *shadowvertex3f;
210
211 int maxshadowmark;
212 int numshadowmark;
213 int *shadowmark;
214 int *shadowmarklist;
215 int shadowmarkcount;
216
217 int maxshadowsides;
218 int numshadowsides;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
221
222 int maxvertexupdate;
223 int *vertexupdate;
224 int *vertexremap;
225 int vertexupdatenum;
226
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;
231
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;
236
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;
241
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_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
252
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingdiffusespecularfbo;
255 GLuint r_shadow_prepasslightingdiffusefbo;
256 int r_shadow_prepass_width;
257 int r_shadow_prepass_height;
258 rtexture_t *r_shadow_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
263
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
266
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
269
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
271
272 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"};
273 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"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
279 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
280 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)"};
281 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"};
282 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
283 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
284 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
285 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
286 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
289 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 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)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 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)"};
297 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"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 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"};
301 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
303 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)"};
304 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"};
305 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)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 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"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 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)"};
321 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
322 cvar_t r_shadow_particletrace = {CVAR_SAVE, "r_shadow_particletrace", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity), requires r_shadow_deferred 1, requires r_shadow_realtime_world 1, EXTREMELY SLOW"};
323 cvar_t r_shadow_particletrace_intensity = {CVAR_SAVE, "r_shadow_particletrace_intensity", "128", "overall brightness of particle traced radiosity"};
324 cvar_t r_shadow_particletrace_size = {CVAR_SAVE, "r_shadow_particletrace_size", "32", "particles produce bounce lights of this radius"};
325 cvar_t r_shadow_particletrace_radiusscale = {CVAR_SAVE, "r_shadow_particletrace_radiusscale", "1", "particles stop at this fraction of light radius"};
326 cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_maxbounce", "1", "maximum number of bounces for a particle (minimum is 1)"};
327 cvar_t r_shadow_particletrace_bounceintensity = {CVAR_SAVE, "r_shadow_particletrace_bounceintensity", "1", "amount of energy carried over after each bounce"};
328 cvar_t r_shadow_particletrace_particlespacing = {CVAR_SAVE, "r_shadow_particletrace_particlespacing", "0.25", "overlap setting in terms of particle size, this affects how many particles are used"};
329 cvar_t r_shadow_particletrace_updatepercentage = {CVAR_SAVE, "r_shadow_particletrace_updatepercentage", "0.01", "update this fraction of the particles of a light each frame (0 = best performance)"};
330 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, requires r_shadow_realtime_world 1"};
331 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
332 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
333 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
334 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
335 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "16", "maximum number of bounces for a particle (minimum is 1)"};
336 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce"};
337 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "16", "brightness of particles contributing to bouncegrid texture"};
338 cvar_t r_shadow_bouncegrid_particlespacing = {CVAR_SAVE, "r_shadow_bouncegrid_particlespacing", "32", "emit one particle per this many units (squared) of radius (squared)"};
339 cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
340 cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
341 cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
342 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
343 cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
344 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "128", "maximum texture size of bouncegrid on X axis"};
345 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "128", "maximum texture size of bouncegrid on Y axis"};
346 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "64", "maximum texture size of bouncegrid on Z axis"};
347 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
348 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
349 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
350 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
351 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
352 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
353 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
354 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
355 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
356 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
357 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
358 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
359
360 rtexture_t *r_shadow_bouncegridtexture;
361 matrix4x4_t r_shadow_bouncegridmatrix;
362 vec_t r_shadow_bouncegridintensity;
363 static double r_shadow_bouncegridtime;
364 static int r_shadow_bouncegridresolution[3];
365
366 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
367 #define ATTENTABLESIZE 256
368 // 1D gradient, 2D circle and 3D sphere attenuation textures
369 #define ATTEN1DSIZE 32
370 #define ATTEN2DSIZE 64
371 #define ATTEN3DSIZE 32
372
373 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
374 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
375 static float r_shadow_attentable[ATTENTABLESIZE+1];
376
377 rtlight_t *r_shadow_compilingrtlight;
378 static memexpandablearray_t r_shadow_worldlightsarray;
379 dlight_t *r_shadow_selectedlight;
380 dlight_t r_shadow_bufferlight;
381 vec3_t r_editlights_cursorlocation;
382 qboolean r_editlights_lockcursor;
383
384 extern int con_vislines;
385
386 void R_Shadow_UncompileWorldLights(void);
387 void R_Shadow_ClearWorldLights(void);
388 void R_Shadow_SaveWorldLights(void);
389 void R_Shadow_LoadWorldLights(void);
390 void R_Shadow_LoadLightsFile(void);
391 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
392 void R_Shadow_EditLights_Reload_f(void);
393 void R_Shadow_ValidateCvars(void);
394 static void R_Shadow_MakeTextures(void);
395
396 #define EDLIGHTSPRSIZE                  8
397 skinframe_t *r_editlights_sprcursor;
398 skinframe_t *r_editlights_sprlight;
399 skinframe_t *r_editlights_sprnoshadowlight;
400 skinframe_t *r_editlights_sprcubemaplight;
401 skinframe_t *r_editlights_sprcubemapnoshadowlight;
402 skinframe_t *r_editlights_sprselection;
403
404 void R_Shadow_SetShadowMode(void)
405 {
406         r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
407         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
408         r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
409         r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
410         r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
411         r_shadow_shadowmaplod = -1;
412         r_shadow_shadowmapsize = 0;
413         r_shadow_shadowmapsampler = false;
414         r_shadow_shadowmappcf = 0;
415         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
416         if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
417         {
418                 switch(vid.renderpath)
419                 {
420                 case RENDERPATH_GL20:
421                         if(r_shadow_shadowmapfilterquality < 0)
422                         {
423                                 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
424                                         r_shadow_shadowmappcf = 1;
425                                 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) 
426                                 {
427                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
428                                         r_shadow_shadowmappcf = 1;
429                                 }
430                                 else if(strstr(gl_vendor, "ATI")) 
431                                         r_shadow_shadowmappcf = 1;
432                                 else 
433                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
434                         }
435                         else 
436                         {
437                                 switch (r_shadow_shadowmapfilterquality)
438                                 {
439                                 case 1:
440                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
441                                         break;
442                                 case 2:
443                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
444                                         r_shadow_shadowmappcf = 1;
445                                         break;
446                                 case 3:
447                                         r_shadow_shadowmappcf = 1;
448                                         break;
449                                 case 4:
450                                         r_shadow_shadowmappcf = 2;
451                                         break;
452                                 }
453                         }
454                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
455                         break;
456                 case RENDERPATH_D3D9:
457                 case RENDERPATH_D3D10:
458                 case RENDERPATH_D3D11:
459                 case RENDERPATH_SOFT:
460                         r_shadow_shadowmapsampler = false;
461                         r_shadow_shadowmappcf = 1;
462                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
463                         break;
464                 case RENDERPATH_GL13:
465                         break;
466                 case RENDERPATH_GL11:
467                         break;
468                 case RENDERPATH_GLES2:
469                         break;
470                 }
471         }
472 }
473
474 qboolean R_Shadow_ShadowMappingEnabled(void)
475 {
476         switch (r_shadow_shadowmode)
477         {
478         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
479                 return true;
480         default:
481                 return false;
482         }
483 }
484
485 void R_Shadow_FreeShadowMaps(void)
486 {
487         R_Shadow_SetShadowMode();
488
489         R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
490
491         r_shadow_fbo2d = 0;
492
493         if (r_shadow_shadowmap2dtexture)
494                 R_FreeTexture(r_shadow_shadowmap2dtexture);
495         r_shadow_shadowmap2dtexture = NULL;
496
497         if (r_shadow_shadowmap2dcolortexture)
498                 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
499         r_shadow_shadowmap2dcolortexture = NULL;
500
501         if (r_shadow_shadowmapvsdcttexture)
502                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
503         r_shadow_shadowmapvsdcttexture = NULL;
504 }
505
506 void r_shadow_start(void)
507 {
508         // allocate vertex processing arrays
509         r_shadow_bouncegridtexture = NULL;
510         r_shadow_attenuationgradienttexture = NULL;
511         r_shadow_attenuation2dtexture = NULL;
512         r_shadow_attenuation3dtexture = NULL;
513         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
514         r_shadow_shadowmap2dtexture = NULL;
515         r_shadow_shadowmap2dcolortexture = NULL;
516         r_shadow_shadowmapvsdcttexture = NULL;
517         r_shadow_shadowmapmaxsize = 0;
518         r_shadow_shadowmapsize = 0;
519         r_shadow_shadowmaplod = 0;
520         r_shadow_shadowmapfilterquality = -1;
521         r_shadow_shadowmapdepthbits = 0;
522         r_shadow_shadowmapvsdct = false;
523         r_shadow_shadowmapsampler = false;
524         r_shadow_shadowmappcf = 0;
525         r_shadow_fbo2d = 0;
526
527         R_Shadow_FreeShadowMaps();
528
529         r_shadow_texturepool = NULL;
530         r_shadow_filters_texturepool = NULL;
531         R_Shadow_ValidateCvars();
532         R_Shadow_MakeTextures();
533         maxshadowtriangles = 0;
534         shadowelements = NULL;
535         maxshadowvertices = 0;
536         shadowvertex3f = NULL;
537         maxvertexupdate = 0;
538         vertexupdate = NULL;
539         vertexremap = NULL;
540         vertexupdatenum = 0;
541         maxshadowmark = 0;
542         numshadowmark = 0;
543         shadowmark = NULL;
544         shadowmarklist = NULL;
545         shadowmarkcount = 0;
546         maxshadowsides = 0;
547         numshadowsides = 0;
548         shadowsides = NULL;
549         shadowsideslist = NULL;
550         r_shadow_buffer_numleafpvsbytes = 0;
551         r_shadow_buffer_visitingleafpvs = NULL;
552         r_shadow_buffer_leafpvs = NULL;
553         r_shadow_buffer_leaflist = NULL;
554         r_shadow_buffer_numsurfacepvsbytes = 0;
555         r_shadow_buffer_surfacepvs = NULL;
556         r_shadow_buffer_surfacelist = NULL;
557         r_shadow_buffer_surfacesides = NULL;
558         r_shadow_buffer_numshadowtrispvsbytes = 0;
559         r_shadow_buffer_shadowtrispvs = NULL;
560         r_shadow_buffer_numlighttrispvsbytes = 0;
561         r_shadow_buffer_lighttrispvs = NULL;
562
563         r_shadow_usingdeferredprepass = false;
564         r_shadow_prepass_width = r_shadow_prepass_height = 0;
565 }
566
567 static void R_Shadow_FreeDeferred(void);
568 void r_shadow_shutdown(void)
569 {
570         CHECKGLERROR
571         R_Shadow_UncompileWorldLights();
572
573         R_Shadow_FreeShadowMaps();
574
575         r_shadow_usingdeferredprepass = false;
576         if (r_shadow_prepass_width)
577                 R_Shadow_FreeDeferred();
578         r_shadow_prepass_width = r_shadow_prepass_height = 0;
579
580         CHECKGLERROR
581         r_shadow_bouncegridtexture = NULL;
582         r_shadow_attenuationgradienttexture = NULL;
583         r_shadow_attenuation2dtexture = NULL;
584         r_shadow_attenuation3dtexture = NULL;
585         R_FreeTexturePool(&r_shadow_texturepool);
586         R_FreeTexturePool(&r_shadow_filters_texturepool);
587         maxshadowtriangles = 0;
588         if (shadowelements)
589                 Mem_Free(shadowelements);
590         shadowelements = NULL;
591         if (shadowvertex3f)
592                 Mem_Free(shadowvertex3f);
593         shadowvertex3f = NULL;
594         maxvertexupdate = 0;
595         if (vertexupdate)
596                 Mem_Free(vertexupdate);
597         vertexupdate = NULL;
598         if (vertexremap)
599                 Mem_Free(vertexremap);
600         vertexremap = NULL;
601         vertexupdatenum = 0;
602         maxshadowmark = 0;
603         numshadowmark = 0;
604         if (shadowmark)
605                 Mem_Free(shadowmark);
606         shadowmark = NULL;
607         if (shadowmarklist)
608                 Mem_Free(shadowmarklist);
609         shadowmarklist = NULL;
610         shadowmarkcount = 0;
611         maxshadowsides = 0;
612         numshadowsides = 0;
613         if (shadowsides)
614                 Mem_Free(shadowsides);
615         shadowsides = NULL;
616         if (shadowsideslist)
617                 Mem_Free(shadowsideslist);
618         shadowsideslist = NULL;
619         r_shadow_buffer_numleafpvsbytes = 0;
620         if (r_shadow_buffer_visitingleafpvs)
621                 Mem_Free(r_shadow_buffer_visitingleafpvs);
622         r_shadow_buffer_visitingleafpvs = NULL;
623         if (r_shadow_buffer_leafpvs)
624                 Mem_Free(r_shadow_buffer_leafpvs);
625         r_shadow_buffer_leafpvs = NULL;
626         if (r_shadow_buffer_leaflist)
627                 Mem_Free(r_shadow_buffer_leaflist);
628         r_shadow_buffer_leaflist = NULL;
629         r_shadow_buffer_numsurfacepvsbytes = 0;
630         if (r_shadow_buffer_surfacepvs)
631                 Mem_Free(r_shadow_buffer_surfacepvs);
632         r_shadow_buffer_surfacepvs = NULL;
633         if (r_shadow_buffer_surfacelist)
634                 Mem_Free(r_shadow_buffer_surfacelist);
635         r_shadow_buffer_surfacelist = NULL;
636         if (r_shadow_buffer_surfacesides)
637                 Mem_Free(r_shadow_buffer_surfacesides);
638         r_shadow_buffer_surfacesides = NULL;
639         r_shadow_buffer_numshadowtrispvsbytes = 0;
640         if (r_shadow_buffer_shadowtrispvs)
641                 Mem_Free(r_shadow_buffer_shadowtrispvs);
642         r_shadow_buffer_numlighttrispvsbytes = 0;
643         if (r_shadow_buffer_lighttrispvs)
644                 Mem_Free(r_shadow_buffer_lighttrispvs);
645 }
646
647 void r_shadow_newmap(void)
648 {
649         if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
650         if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
651         if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
652         if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
653         if (r_editlights_sprnoshadowlight)        R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
654         if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
655         if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
656         if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
657         if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
658                 R_Shadow_EditLights_Reload_f();
659 }
660
661 void R_Shadow_Init(void)
662 {
663         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
664         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
665         Cvar_RegisterVariable(&r_shadow_usebihculling);
666         Cvar_RegisterVariable(&r_shadow_usenormalmap);
667         Cvar_RegisterVariable(&r_shadow_debuglight);
668         Cvar_RegisterVariable(&r_shadow_deferred);
669         Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
670 //      Cvar_RegisterVariable(&r_shadow_deferred_fp);
671         Cvar_RegisterVariable(&r_shadow_gloss);
672         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
673         Cvar_RegisterVariable(&r_shadow_glossintensity);
674         Cvar_RegisterVariable(&r_shadow_glossexponent);
675         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
676         Cvar_RegisterVariable(&r_shadow_glossexact);
677         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
678         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
679         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
680         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
681         Cvar_RegisterVariable(&r_shadow_projectdistance);
682         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
683         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
684         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
685         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
686         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
687         Cvar_RegisterVariable(&r_shadow_realtime_world);
688         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
689         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
690         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
691         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
692         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
693         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
694         Cvar_RegisterVariable(&r_shadow_scissor);
695         Cvar_RegisterVariable(&r_shadow_shadowmapping);
696         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
697         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
698         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
699         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
700         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
701         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
702 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
703 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
704         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
705         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
706         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
707         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
708         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
709         Cvar_RegisterVariable(&r_shadow_sortsurfaces);
710         Cvar_RegisterVariable(&r_shadow_polygonfactor);
711         Cvar_RegisterVariable(&r_shadow_polygonoffset);
712         Cvar_RegisterVariable(&r_shadow_texture3d);
713         Cvar_RegisterVariable(&r_shadow_particletrace);
714         Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
715         Cvar_RegisterVariable(&r_shadow_particletrace_size);
716         Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
717         Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
718         Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
719         Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
720         Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
721         Cvar_RegisterVariable(&r_shadow_bouncegrid);
722         Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
723         Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
724         Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
725         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
726         Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
727         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
728         Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
729         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
730         Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
731         Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
732         Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
733         Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
734         Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
735         Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
736         Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
737         Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
738         Cvar_RegisterVariable(&r_coronas);
739         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
740         Cvar_RegisterVariable(&r_coronas_occlusionquery);
741         Cvar_RegisterVariable(&gl_flashblend);
742         Cvar_RegisterVariable(&gl_ext_separatestencil);
743         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
744         if (gamemode == GAME_TENEBRAE)
745         {
746                 Cvar_SetValue("r_shadow_gloss", 2);
747                 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
748         }
749         R_Shadow_EditLights_Init();
750         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
751         maxshadowtriangles = 0;
752         shadowelements = NULL;
753         maxshadowvertices = 0;
754         shadowvertex3f = NULL;
755         maxvertexupdate = 0;
756         vertexupdate = NULL;
757         vertexremap = NULL;
758         vertexupdatenum = 0;
759         maxshadowmark = 0;
760         numshadowmark = 0;
761         shadowmark = NULL;
762         shadowmarklist = NULL;
763         shadowmarkcount = 0;
764         maxshadowsides = 0;
765         numshadowsides = 0;
766         shadowsides = NULL;
767         shadowsideslist = NULL;
768         r_shadow_buffer_numleafpvsbytes = 0;
769         r_shadow_buffer_visitingleafpvs = NULL;
770         r_shadow_buffer_leafpvs = NULL;
771         r_shadow_buffer_leaflist = NULL;
772         r_shadow_buffer_numsurfacepvsbytes = 0;
773         r_shadow_buffer_surfacepvs = NULL;
774         r_shadow_buffer_surfacelist = NULL;
775         r_shadow_buffer_surfacesides = NULL;
776         r_shadow_buffer_shadowtrispvs = NULL;
777         r_shadow_buffer_lighttrispvs = NULL;
778         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
779 }
780
781 matrix4x4_t matrix_attenuationxyz =
782 {
783         {
784                 {0.5, 0.0, 0.0, 0.5},
785                 {0.0, 0.5, 0.0, 0.5},
786                 {0.0, 0.0, 0.5, 0.5},
787                 {0.0, 0.0, 0.0, 1.0}
788         }
789 };
790
791 matrix4x4_t matrix_attenuationz =
792 {
793         {
794                 {0.0, 0.0, 0.5, 0.5},
795                 {0.0, 0.0, 0.0, 0.5},
796                 {0.0, 0.0, 0.0, 0.5},
797                 {0.0, 0.0, 0.0, 1.0}
798         }
799 };
800
801 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
802 {
803         numvertices = ((numvertices + 255) & ~255) * vertscale;
804         numtriangles = ((numtriangles + 255) & ~255) * triscale;
805         // make sure shadowelements is big enough for this volume
806         if (maxshadowtriangles < numtriangles)
807         {
808                 maxshadowtriangles = numtriangles;
809                 if (shadowelements)
810                         Mem_Free(shadowelements);
811                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
812         }
813         // make sure shadowvertex3f is big enough for this volume
814         if (maxshadowvertices < numvertices)
815         {
816                 maxshadowvertices = numvertices;
817                 if (shadowvertex3f)
818                         Mem_Free(shadowvertex3f);
819                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
820         }
821 }
822
823 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
824 {
825         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
826         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
827         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
828         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
829         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
830         {
831                 if (r_shadow_buffer_visitingleafpvs)
832                         Mem_Free(r_shadow_buffer_visitingleafpvs);
833                 if (r_shadow_buffer_leafpvs)
834                         Mem_Free(r_shadow_buffer_leafpvs);
835                 if (r_shadow_buffer_leaflist)
836                         Mem_Free(r_shadow_buffer_leaflist);
837                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
838                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
839                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
840                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
841         }
842         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
843         {
844                 if (r_shadow_buffer_surfacepvs)
845                         Mem_Free(r_shadow_buffer_surfacepvs);
846                 if (r_shadow_buffer_surfacelist)
847                         Mem_Free(r_shadow_buffer_surfacelist);
848                 if (r_shadow_buffer_surfacesides)
849                         Mem_Free(r_shadow_buffer_surfacesides);
850                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
851                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
852                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
853                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
854         }
855         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
856         {
857                 if (r_shadow_buffer_shadowtrispvs)
858                         Mem_Free(r_shadow_buffer_shadowtrispvs);
859                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
860                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
861         }
862         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
863         {
864                 if (r_shadow_buffer_lighttrispvs)
865                         Mem_Free(r_shadow_buffer_lighttrispvs);
866                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
867                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
868         }
869 }
870
871 void R_Shadow_PrepareShadowMark(int numtris)
872 {
873         // make sure shadowmark is big enough for this volume
874         if (maxshadowmark < numtris)
875         {
876                 maxshadowmark = numtris;
877                 if (shadowmark)
878                         Mem_Free(shadowmark);
879                 if (shadowmarklist)
880                         Mem_Free(shadowmarklist);
881                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
882                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
883                 shadowmarkcount = 0;
884         }
885         shadowmarkcount++;
886         // if shadowmarkcount wrapped we clear the array and adjust accordingly
887         if (shadowmarkcount == 0)
888         {
889                 shadowmarkcount = 1;
890                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
891         }
892         numshadowmark = 0;
893 }
894
895 void R_Shadow_PrepareShadowSides(int numtris)
896 {
897     if (maxshadowsides < numtris)
898     {
899         maxshadowsides = numtris;
900         if (shadowsides)
901                         Mem_Free(shadowsides);
902                 if (shadowsideslist)
903                         Mem_Free(shadowsideslist);
904                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
905                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
906         }
907         numshadowsides = 0;
908 }
909
910 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)
911 {
912         int i, j;
913         int outtriangles = 0, outvertices = 0;
914         const int *element;
915         const float *vertex;
916         float ratio, direction[3], projectvector[3];
917
918         if (projectdirection)
919                 VectorScale(projectdirection, projectdistance, projectvector);
920         else
921                 VectorClear(projectvector);
922
923         // create the vertices
924         if (projectdirection)
925         {
926                 for (i = 0;i < numshadowmarktris;i++)
927                 {
928                         element = inelement3i + shadowmarktris[i] * 3;
929                         for (j = 0;j < 3;j++)
930                         {
931                                 if (vertexupdate[element[j]] != vertexupdatenum)
932                                 {
933                                         vertexupdate[element[j]] = vertexupdatenum;
934                                         vertexremap[element[j]] = outvertices;
935                                         vertex = invertex3f + element[j] * 3;
936                                         // project one copy of the vertex according to projectvector
937                                         VectorCopy(vertex, outvertex3f);
938                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
939                                         outvertex3f += 6;
940                                         outvertices += 2;
941                                 }
942                         }
943                 }
944         }
945         else
946         {
947                 for (i = 0;i < numshadowmarktris;i++)
948                 {
949                         element = inelement3i + shadowmarktris[i] * 3;
950                         for (j = 0;j < 3;j++)
951                         {
952                                 if (vertexupdate[element[j]] != vertexupdatenum)
953                                 {
954                                         vertexupdate[element[j]] = vertexupdatenum;
955                                         vertexremap[element[j]] = outvertices;
956                                         vertex = invertex3f + element[j] * 3;
957                                         // project one copy of the vertex to the sphere radius of the light
958                                         // (FIXME: would projecting it to the light box be better?)
959                                         VectorSubtract(vertex, projectorigin, direction);
960                                         ratio = projectdistance / VectorLength(direction);
961                                         VectorCopy(vertex, outvertex3f);
962                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
963                                         outvertex3f += 6;
964                                         outvertices += 2;
965                                 }
966                         }
967                 }
968         }
969
970         if (r_shadow_frontsidecasting.integer)
971         {
972                 for (i = 0;i < numshadowmarktris;i++)
973                 {
974                         int remappedelement[3];
975                         int markindex;
976                         const int *neighbortriangle;
977
978                         markindex = shadowmarktris[i] * 3;
979                         element = inelement3i + markindex;
980                         neighbortriangle = inneighbor3i + markindex;
981                         // output the front and back triangles
982                         outelement3i[0] = vertexremap[element[0]];
983                         outelement3i[1] = vertexremap[element[1]];
984                         outelement3i[2] = vertexremap[element[2]];
985                         outelement3i[3] = vertexremap[element[2]] + 1;
986                         outelement3i[4] = vertexremap[element[1]] + 1;
987                         outelement3i[5] = vertexremap[element[0]] + 1;
988
989                         outelement3i += 6;
990                         outtriangles += 2;
991                         // output the sides (facing outward from this triangle)
992                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
993                         {
994                                 remappedelement[0] = vertexremap[element[0]];
995                                 remappedelement[1] = vertexremap[element[1]];
996                                 outelement3i[0] = remappedelement[1];
997                                 outelement3i[1] = remappedelement[0];
998                                 outelement3i[2] = remappedelement[0] + 1;
999                                 outelement3i[3] = remappedelement[1];
1000                                 outelement3i[4] = remappedelement[0] + 1;
1001                                 outelement3i[5] = remappedelement[1] + 1;
1002
1003                                 outelement3i += 6;
1004                                 outtriangles += 2;
1005                         }
1006                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1007                         {
1008                                 remappedelement[1] = vertexremap[element[1]];
1009                                 remappedelement[2] = vertexremap[element[2]];
1010                                 outelement3i[0] = remappedelement[2];
1011                                 outelement3i[1] = remappedelement[1];
1012                                 outelement3i[2] = remappedelement[1] + 1;
1013                                 outelement3i[3] = remappedelement[2];
1014                                 outelement3i[4] = remappedelement[1] + 1;
1015                                 outelement3i[5] = remappedelement[2] + 1;
1016
1017                                 outelement3i += 6;
1018                                 outtriangles += 2;
1019                         }
1020                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1021                         {
1022                                 remappedelement[0] = vertexremap[element[0]];
1023                                 remappedelement[2] = vertexremap[element[2]];
1024                                 outelement3i[0] = remappedelement[0];
1025                                 outelement3i[1] = remappedelement[2];
1026                                 outelement3i[2] = remappedelement[2] + 1;
1027                                 outelement3i[3] = remappedelement[0];
1028                                 outelement3i[4] = remappedelement[2] + 1;
1029                                 outelement3i[5] = remappedelement[0] + 1;
1030
1031                                 outelement3i += 6;
1032                                 outtriangles += 2;
1033                         }
1034                 }
1035         }
1036         else
1037         {
1038                 for (i = 0;i < numshadowmarktris;i++)
1039                 {
1040                         int remappedelement[3];
1041                         int markindex;
1042                         const int *neighbortriangle;
1043
1044                         markindex = shadowmarktris[i] * 3;
1045                         element = inelement3i + markindex;
1046                         neighbortriangle = inneighbor3i + markindex;
1047                         // output the front and back triangles
1048                         outelement3i[0] = vertexremap[element[2]];
1049                         outelement3i[1] = vertexremap[element[1]];
1050                         outelement3i[2] = vertexremap[element[0]];
1051                         outelement3i[3] = vertexremap[element[0]] + 1;
1052                         outelement3i[4] = vertexremap[element[1]] + 1;
1053                         outelement3i[5] = vertexremap[element[2]] + 1;
1054
1055                         outelement3i += 6;
1056                         outtriangles += 2;
1057                         // output the sides (facing outward from this triangle)
1058                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1059                         {
1060                                 remappedelement[0] = vertexremap[element[0]];
1061                                 remappedelement[1] = vertexremap[element[1]];
1062                                 outelement3i[0] = remappedelement[0];
1063                                 outelement3i[1] = remappedelement[1];
1064                                 outelement3i[2] = remappedelement[1] + 1;
1065                                 outelement3i[3] = remappedelement[0];
1066                                 outelement3i[4] = remappedelement[1] + 1;
1067                                 outelement3i[5] = remappedelement[0] + 1;
1068
1069                                 outelement3i += 6;
1070                                 outtriangles += 2;
1071                         }
1072                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1073                         {
1074                                 remappedelement[1] = vertexremap[element[1]];
1075                                 remappedelement[2] = vertexremap[element[2]];
1076                                 outelement3i[0] = remappedelement[1];
1077                                 outelement3i[1] = remappedelement[2];
1078                                 outelement3i[2] = remappedelement[2] + 1;
1079                                 outelement3i[3] = remappedelement[1];
1080                                 outelement3i[4] = remappedelement[2] + 1;
1081                                 outelement3i[5] = remappedelement[1] + 1;
1082
1083                                 outelement3i += 6;
1084                                 outtriangles += 2;
1085                         }
1086                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1087                         {
1088                                 remappedelement[0] = vertexremap[element[0]];
1089                                 remappedelement[2] = vertexremap[element[2]];
1090                                 outelement3i[0] = remappedelement[2];
1091                                 outelement3i[1] = remappedelement[0];
1092                                 outelement3i[2] = remappedelement[0] + 1;
1093                                 outelement3i[3] = remappedelement[2];
1094                                 outelement3i[4] = remappedelement[0] + 1;
1095                                 outelement3i[5] = remappedelement[2] + 1;
1096
1097                                 outelement3i += 6;
1098                                 outtriangles += 2;
1099                         }
1100                 }
1101         }
1102         if (outnumvertices)
1103                 *outnumvertices = outvertices;
1104         return outtriangles;
1105 }
1106
1107 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)
1108 {
1109         int i, j, k;
1110         int outtriangles = 0, outvertices = 0;
1111         const int *element;
1112         const float *vertex;
1113         float ratio, direction[3], projectvector[3];
1114         qboolean side[4];
1115
1116         if (projectdirection)
1117                 VectorScale(projectdirection, projectdistance, projectvector);
1118         else
1119                 VectorClear(projectvector);
1120
1121         for (i = 0;i < numshadowmarktris;i++)
1122         {
1123                 int remappedelement[3];
1124                 int markindex;
1125                 const int *neighbortriangle;
1126
1127                 markindex = shadowmarktris[i] * 3;
1128                 neighbortriangle = inneighbor3i + markindex;
1129                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1130                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1131                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1132                 if (side[0] + side[1] + side[2] == 0)
1133                         continue;
1134
1135                 side[3] = side[0];
1136                 element = inelement3i + markindex;
1137
1138                 // create the vertices
1139                 for (j = 0;j < 3;j++)
1140                 {
1141                         if (side[j] + side[j+1] == 0)
1142                                 continue;
1143                         k = element[j];
1144                         if (vertexupdate[k] != vertexupdatenum)
1145                         {
1146                                 vertexupdate[k] = vertexupdatenum;
1147                                 vertexremap[k] = outvertices;
1148                                 vertex = invertex3f + k * 3;
1149                                 VectorCopy(vertex, outvertex3f);
1150                                 if (projectdirection)
1151                                 {
1152                                         // project one copy of the vertex according to projectvector
1153                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
1154                                 }
1155                                 else
1156                                 {
1157                                         // project one copy of the vertex to the sphere radius of the light
1158                                         // (FIXME: would projecting it to the light box be better?)
1159                                         VectorSubtract(vertex, projectorigin, direction);
1160                                         ratio = projectdistance / VectorLength(direction);
1161                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1162                                 }
1163                                 outvertex3f += 6;
1164                                 outvertices += 2;
1165                         }
1166                 }
1167
1168                 // output the sides (facing outward from this triangle)
1169                 if (!side[0])
1170                 {
1171                         remappedelement[0] = vertexremap[element[0]];
1172                         remappedelement[1] = vertexremap[element[1]];
1173                         outelement3i[0] = remappedelement[1];
1174                         outelement3i[1] = remappedelement[0];
1175                         outelement3i[2] = remappedelement[0] + 1;
1176                         outelement3i[3] = remappedelement[1];
1177                         outelement3i[4] = remappedelement[0] + 1;
1178                         outelement3i[5] = remappedelement[1] + 1;
1179
1180                         outelement3i += 6;
1181                         outtriangles += 2;
1182                 }
1183                 if (!side[1])
1184                 {
1185                         remappedelement[1] = vertexremap[element[1]];
1186                         remappedelement[2] = vertexremap[element[2]];
1187                         outelement3i[0] = remappedelement[2];
1188                         outelement3i[1] = remappedelement[1];
1189                         outelement3i[2] = remappedelement[1] + 1;
1190                         outelement3i[3] = remappedelement[2];
1191                         outelement3i[4] = remappedelement[1] + 1;
1192                         outelement3i[5] = remappedelement[2] + 1;
1193
1194                         outelement3i += 6;
1195                         outtriangles += 2;
1196                 }
1197                 if (!side[2])
1198                 {
1199                         remappedelement[0] = vertexremap[element[0]];
1200                         remappedelement[2] = vertexremap[element[2]];
1201                         outelement3i[0] = remappedelement[0];
1202                         outelement3i[1] = remappedelement[2];
1203                         outelement3i[2] = remappedelement[2] + 1;
1204                         outelement3i[3] = remappedelement[0];
1205                         outelement3i[4] = remappedelement[2] + 1;
1206                         outelement3i[5] = remappedelement[0] + 1;
1207
1208                         outelement3i += 6;
1209                         outtriangles += 2;
1210                 }
1211         }
1212         if (outnumvertices)
1213                 *outnumvertices = outvertices;
1214         return outtriangles;
1215 }
1216
1217 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)
1218 {
1219         int t, tend;
1220         const int *e;
1221         const float *v[3];
1222         float normal[3];
1223         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1224                 return;
1225         tend = firsttriangle + numtris;
1226         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1227         {
1228                 // surface box entirely inside light box, no box cull
1229                 if (projectdirection)
1230                 {
1231                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1232                         {
1233                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1234                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1235                                         shadowmarklist[numshadowmark++] = t;
1236                         }
1237                 }
1238                 else
1239                 {
1240                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1241                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1242                                         shadowmarklist[numshadowmark++] = t;
1243                 }
1244         }
1245         else
1246         {
1247                 // surface box not entirely inside light box, cull each triangle
1248                 if (projectdirection)
1249                 {
1250                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1251                         {
1252                                 v[0] = invertex3f + e[0] * 3;
1253                                 v[1] = invertex3f + e[1] * 3;
1254                                 v[2] = invertex3f + e[2] * 3;
1255                                 TriangleNormal(v[0], v[1], v[2], normal);
1256                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1257                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1258                                         shadowmarklist[numshadowmark++] = t;
1259                         }
1260                 }
1261                 else
1262                 {
1263                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1264                         {
1265                                 v[0] = invertex3f + e[0] * 3;
1266                                 v[1] = invertex3f + e[1] * 3;
1267                                 v[2] = invertex3f + e[2] * 3;
1268                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1269                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1270                                         shadowmarklist[numshadowmark++] = t;
1271                         }
1272                 }
1273         }
1274 }
1275
1276 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1277 {
1278 #if 1
1279         return false;
1280 #else
1281         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1282                 return false;
1283         // check if the shadow volume intersects the near plane
1284         //
1285         // a ray between the eye and light origin may intersect the caster,
1286         // indicating that the shadow may touch the eye location, however we must
1287         // test the near plane (a polygon), not merely the eye location, so it is
1288         // easiest to enlarge the caster bounding shape slightly for this.
1289         // TODO
1290         return true;
1291 #endif
1292 }
1293
1294 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)
1295 {
1296         int i, tris, outverts;
1297         if (projectdistance < 0.1)
1298         {
1299                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1300                 return;
1301         }
1302         if (!numverts || !nummarktris)
1303                 return;
1304         // make sure shadowelements is big enough for this volume
1305         if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1306                 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1307
1308         if (maxvertexupdate < numverts)
1309         {
1310                 maxvertexupdate = numverts;
1311                 if (vertexupdate)
1312                         Mem_Free(vertexupdate);
1313                 if (vertexremap)
1314                         Mem_Free(vertexremap);
1315                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1316                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1317                 vertexupdatenum = 0;
1318         }
1319         vertexupdatenum++;
1320         if (vertexupdatenum == 0)
1321         {
1322                 vertexupdatenum = 1;
1323                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1324                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1325         }
1326
1327         for (i = 0;i < nummarktris;i++)
1328                 shadowmark[marktris[i]] = shadowmarkcount;
1329
1330         if (r_shadow_compilingrtlight)
1331         {
1332                 // if we're compiling an rtlight, capture the mesh
1333                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1334                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1335                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1336                 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1337         }
1338         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1339         {
1340                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1341                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1342                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1343         }
1344         else
1345         {
1346                 // decide which type of shadow to generate and set stencil mode
1347                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1348                 // generate the sides or a solid volume, depending on type
1349                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1350                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1351                 else
1352                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1353                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1354                 r_refdef.stats.lights_shadowtriangles += tris;
1355                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1356                 {
1357                         // increment stencil if frontface is infront of depthbuffer
1358                         GL_CullFace(r_refdef.view.cullface_front);
1359                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1360                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1361                         // decrement stencil if backface is infront of depthbuffer
1362                         GL_CullFace(r_refdef.view.cullface_back);
1363                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1364                 }
1365                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1366                 {
1367                         // decrement stencil if backface is behind depthbuffer
1368                         GL_CullFace(r_refdef.view.cullface_front);
1369                         R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1370                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1371                         // increment stencil if frontface is behind depthbuffer
1372                         GL_CullFace(r_refdef.view.cullface_back);
1373                         R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1374                 }
1375                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1376                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1377         }
1378 }
1379
1380 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1381 {
1382     // p1, p2, p3 are in the cubemap's local coordinate system
1383     // bias = border/(size - border)
1384         int mask = 0x3F;
1385
1386     float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1387           dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1388           dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1389         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1390         mask &= (3<<4)
1391                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1392                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1393                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1394     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1395         mask &= (3<<4)
1396             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1397             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))            
1398             | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1399
1400     dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1401     dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1402     dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1403     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1404         mask &= (3<<0)
1405             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1406             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))            
1407             | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1408     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1409         mask &= (3<<0)
1410             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1411             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1412             | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1413
1414     dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1415     dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1416     dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1417     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1418         mask &= (3<<2)
1419             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1420             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1421             | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1422     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1423         mask &= (3<<2)
1424             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1425             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1426             | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1427
1428         return mask;
1429 }
1430
1431 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1432 {
1433         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1434         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1435         int mask = 0x3F;
1436
1437         VectorSubtract(maxs, mins, radius);
1438     VectorScale(radius, 0.5f, radius);
1439     VectorAdd(mins, radius, center);
1440     Matrix4x4_Transform(worldtolight, center, lightcenter);
1441         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1442         VectorSubtract(lightcenter, lightradius, pmin);
1443         VectorAdd(lightcenter, lightradius, pmax);
1444
1445     dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1446     dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1447     if(ap1 > bias*an1 && ap2 > bias*an2)
1448         mask &= (3<<4)
1449             | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1450             | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1451     if(an1 > bias*ap1 && an2 > bias*ap2)
1452         mask &= (3<<4)
1453             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1454             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1455
1456     dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1457     dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1458     if(ap1 > bias*an1 && ap2 > bias*an2)
1459         mask &= (3<<0)
1460             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1461             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1462     if(an1 > bias*ap1 && an2 > bias*ap2)
1463         mask &= (3<<0)
1464             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1465             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1466
1467     dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1468     dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1469     if(ap1 > bias*an1 && ap2 > bias*an2)
1470         mask &= (3<<2)
1471             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1472             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1473     if(an1 > bias*ap1 && an2 > bias*ap2)
1474         mask &= (3<<2)
1475             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1476             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1477
1478     return mask;
1479 }
1480
1481 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1482
1483 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1484 {
1485     // p is in the cubemap's local coordinate system
1486     // bias = border/(size - border)
1487     float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1488     float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1489     float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1490     int mask = 0x3F;
1491     if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1492     if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1493     if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1494     if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1495     if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1496     if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1497     return mask;
1498 }
1499
1500 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1501 {
1502         int i;
1503         vec3_t p, n;
1504         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1505         float scale = (size - 2*border)/size, len;
1506         float bias = border / (float)(size - border), dp, dn, ap, an;
1507         // check if cone enclosing side would cross frustum plane 
1508         scale = 2 / (scale*scale + 2);
1509         for (i = 0;i < 5;i++)
1510         {
1511                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1512                         continue;
1513                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1514                 len = scale*VectorLength2(n);
1515                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1516                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1517                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1518         }
1519         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1520         {
1521         Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1522         len = scale*VectorLength(n);
1523                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1524                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1525                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1526         }
1527         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1528         // check if frustum corners/origin cross plane sides
1529 #if 1
1530     // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1531     Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1532     dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1533     masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1534     masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1535     dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1536     masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1537     masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1538     dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1539     masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1540     masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1541     for (i = 0;i < 4;i++)
1542     {
1543         Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1544         VectorSubtract(n, p, n);
1545         dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1546         if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1547         if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1548         dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1549         if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1550         if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1551         dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1552         if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1553         if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1554     }
1555 #else
1556     // finite version, assumes corners are a finite distance from origin dependent on far plane
1557         for (i = 0;i < 5;i++)
1558         {
1559                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1560                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1561                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1562                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1563                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1564                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1565                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1566                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1567                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1568                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1569         }
1570 #endif
1571         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1572 }
1573
1574 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)
1575 {
1576         int t, tend;
1577         const int *e;
1578         const float *v[3];
1579         float normal[3];
1580         vec3_t p[3];
1581         float bias;
1582         int mask, surfacemask = 0;
1583         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1584                 return 0;
1585         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1586         tend = firsttriangle + numtris;
1587         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1588         {
1589                 // surface box entirely inside light box, no box cull
1590                 if (projectdirection)
1591                 {
1592                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1593                         {
1594                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1595                                 TriangleNormal(v[0], v[1], v[2], normal);
1596                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1597                                 {
1598                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1599                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1600                                         surfacemask |= mask;
1601                                         if(totals)
1602                                         {
1603                                                 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;
1604                                                 shadowsides[numshadowsides] = mask;
1605                                                 shadowsideslist[numshadowsides++] = t;
1606                                         }
1607                                 }
1608                         }
1609                 }
1610                 else
1611                 {
1612                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1613                         {
1614                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1615                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1616                                 {
1617                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1618                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1619                                         surfacemask |= mask;
1620                                         if(totals)
1621                                         {
1622                                                 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;
1623                                                 shadowsides[numshadowsides] = mask;
1624                                                 shadowsideslist[numshadowsides++] = t;
1625                                         }
1626                                 }
1627                         }
1628                 }
1629         }
1630         else
1631         {
1632                 // surface box not entirely inside light box, cull each triangle
1633                 if (projectdirection)
1634                 {
1635                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1636                         {
1637                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1638                                 TriangleNormal(v[0], v[1], v[2], normal);
1639                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1640                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1641                                 {
1642                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1643                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1644                                         surfacemask |= mask;
1645                                         if(totals)
1646                                         {
1647                                                 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;
1648                                                 shadowsides[numshadowsides] = mask;
1649                                                 shadowsideslist[numshadowsides++] = t;
1650                                         }
1651                                 }
1652                         }
1653                 }
1654                 else
1655                 {
1656                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1657                         {
1658                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1659                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1660                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1661                                 {
1662                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1663                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1664                                         surfacemask |= mask;
1665                                         if(totals)
1666                                         {
1667                                                 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;
1668                                                 shadowsides[numshadowsides] = mask;
1669                                                 shadowsideslist[numshadowsides++] = t;
1670                                         }
1671                                 }
1672                         }
1673                 }
1674         }
1675         return surfacemask;
1676 }
1677
1678 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)
1679 {
1680         int i, j, outtriangles = 0;
1681         int *outelement3i[6];
1682         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1683                 return;
1684         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1685         // make sure shadowelements is big enough for this mesh
1686         if (maxshadowtriangles < outtriangles)
1687                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1688
1689         // compute the offset and size of the separate index lists for each cubemap side
1690         outtriangles = 0;
1691         for (i = 0;i < 6;i++)
1692         {
1693                 outelement3i[i] = shadowelements + outtriangles * 3;
1694                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1695                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1696                 outtriangles += sidetotals[i];
1697         }
1698
1699         // gather up the (sparse) triangles into separate index lists for each cubemap side
1700         for (i = 0;i < numsidetris;i++)
1701         {
1702                 const int *element = elements + sidetris[i] * 3;
1703                 for (j = 0;j < 6;j++)
1704                 {
1705                         if (sides[i] & (1 << j))
1706                         {
1707                                 outelement3i[j][0] = element[0];
1708                                 outelement3i[j][1] = element[1];
1709                                 outelement3i[j][2] = element[2];
1710                                 outelement3i[j] += 3;
1711                         }
1712                 }
1713         }
1714                         
1715         Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1716 }
1717
1718 static void R_Shadow_MakeTextures_MakeCorona(void)
1719 {
1720         float dx, dy;
1721         int x, y, a;
1722         unsigned char pixels[32][32][4];
1723         for (y = 0;y < 32;y++)
1724         {
1725                 dy = (y - 15.5f) * (1.0f / 16.0f);
1726                 for (x = 0;x < 32;x++)
1727                 {
1728                         dx = (x - 15.5f) * (1.0f / 16.0f);
1729                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1730                         a = bound(0, a, 255);
1731                         pixels[y][x][0] = a;
1732                         pixels[y][x][1] = a;
1733                         pixels[y][x][2] = a;
1734                         pixels[y][x][3] = 255;
1735                 }
1736         }
1737         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1738 }
1739
1740 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1741 {
1742         float dist = sqrt(x*x+y*y+z*z);
1743         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1744         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1745         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1746 }
1747
1748 static void R_Shadow_MakeTextures(void)
1749 {
1750         int x, y, z;
1751         float intensity, dist;
1752         unsigned int *data;
1753         R_Shadow_FreeShadowMaps();
1754         R_FreeTexturePool(&r_shadow_texturepool);
1755         r_shadow_texturepool = R_AllocTexturePool();
1756         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1757         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1758         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1759         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1760         for (x = 0;x <= ATTENTABLESIZE;x++)
1761         {
1762                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1763                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1764                 r_shadow_attentable[x] = bound(0, intensity, 1);
1765         }
1766         // 1D gradient texture
1767         for (x = 0;x < ATTEN1DSIZE;x++)
1768                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1769         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1770         // 2D circle texture
1771         for (y = 0;y < ATTEN2DSIZE;y++)
1772                 for (x = 0;x < ATTEN2DSIZE;x++)
1773                         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);
1774         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1775         // 3D sphere texture
1776         if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1777         {
1778                 for (z = 0;z < ATTEN3DSIZE;z++)
1779                         for (y = 0;y < ATTEN3DSIZE;y++)
1780                                 for (x = 0;x < ATTEN3DSIZE;x++)
1781                                         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));
1782                 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1783         }
1784         else
1785                 r_shadow_attenuation3dtexture = NULL;
1786         Mem_Free(data);
1787
1788         R_Shadow_MakeTextures_MakeCorona();
1789
1790         // Editor light sprites
1791         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1792         "................"
1793         ".3............3."
1794         "..5...2332...5.."
1795         "...7.3....3.7..."
1796         "....7......7...."
1797         "...3.7....7.3..."
1798         "..2...7..7...2.."
1799         "..3..........3.."
1800         "..3..........3.."
1801         "..2...7..7...2.."
1802         "...3.7....7.3..."
1803         "....7......7...."
1804         "...7.3....3.7..."
1805         "..5...2332...5.."
1806         ".3............3."
1807         "................"
1808         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1809         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1810         "................"
1811         "................"
1812         "......1111......"
1813         "....11233211...."
1814         "...1234554321..."
1815         "...1356776531..."
1816         "..124677776421.."
1817         "..135777777531.."
1818         "..135777777531.."
1819         "..124677776421.."
1820         "...1356776531..."
1821         "...1234554321..."
1822         "....11233211...."
1823         "......1111......"
1824         "................"
1825         "................"
1826         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1827         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1828         "................"
1829         "................"
1830         "......1111......"
1831         "....11233211...."
1832         "...1234554321..."
1833         "...1356226531..."
1834         "..12462..26421.."
1835         "..1352....2531.."
1836         "..1352....2531.."
1837         "..12462..26421.."
1838         "...1356226531..."
1839         "...1234554321..."
1840         "....11233211...."
1841         "......1111......"
1842         "................"
1843         "................"
1844         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1845         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1846         "................"
1847         "................"
1848         "......2772......"
1849         "....27755772...."
1850         "..277533335772.."
1851         "..753333333357.."
1852         "..777533335777.."
1853         "..735775577537.."
1854         "..733357753337.."
1855         "..733337733337.."
1856         "..753337733357.."
1857         "..277537735772.."
1858         "....27777772...."
1859         "......2772......"
1860         "................"
1861         "................"
1862         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1863         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1864         "................"
1865         "................"
1866         "......2772......"
1867         "....27722772...."
1868         "..2772....2772.."
1869         "..72........27.."
1870         "..7772....2777.."
1871         "..7.27722772.7.."
1872         "..7...2772...7.."
1873         "..7....77....7.."
1874         "..72...77...27.."
1875         "..2772.77.2772.."
1876         "....27777772...."
1877         "......2772......"
1878         "................"
1879         "................"
1880         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1881         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1882         "................"
1883         ".777752..257777."
1884         ".742........247."
1885         ".72..........27."
1886         ".7............7."
1887         ".5............5."
1888         ".2............2."
1889         "................"
1890         "................"
1891         ".2............2."
1892         ".5............5."
1893         ".7............7."
1894         ".72..........27."
1895         ".742........247."
1896         ".777752..257777."
1897         "................"
1898         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1899 }
1900
1901 void R_Shadow_ValidateCvars(void)
1902 {
1903         if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1904                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1905         if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1906                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1907         if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1908                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1909 }
1910
1911 void R_Shadow_RenderMode_Begin(void)
1912 {
1913 #if 0
1914         GLint drawbuffer;
1915         GLint readbuffer;
1916 #endif
1917         R_Shadow_ValidateCvars();
1918
1919         if (!r_shadow_attenuation2dtexture
1920          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1921          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1922          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1923                 R_Shadow_MakeTextures();
1924
1925         CHECKGLERROR
1926         R_Mesh_ResetTextureState();
1927         GL_BlendFunc(GL_ONE, GL_ZERO);
1928         GL_DepthRange(0, 1);
1929         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1930         GL_DepthTest(true);
1931         GL_DepthMask(false);
1932         GL_Color(0, 0, 0, 1);
1933         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1934
1935         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1936
1937         if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1938         {
1939                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1940                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1941         }
1942         else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1943         {
1944                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1945                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1946         }
1947         else
1948         {
1949                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1950                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1951         }
1952
1953         switch(vid.renderpath)
1954         {
1955         case RENDERPATH_GL20:
1956         case RENDERPATH_D3D9:
1957         case RENDERPATH_D3D10:
1958         case RENDERPATH_D3D11:
1959         case RENDERPATH_SOFT:
1960         case RENDERPATH_GLES2:
1961                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1962                 break;
1963         case RENDERPATH_GL13:
1964         case RENDERPATH_GL11:
1965                 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1966                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1967                 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1968                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1969                 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1970                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1971                 else
1972                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1973                 break;
1974         }
1975
1976         CHECKGLERROR
1977 #if 0
1978         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1979         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1980         r_shadow_drawbuffer = drawbuffer;
1981         r_shadow_readbuffer = readbuffer;
1982 #endif
1983         r_shadow_cullface_front = r_refdef.view.cullface_front;
1984         r_shadow_cullface_back = r_refdef.view.cullface_back;
1985 }
1986
1987 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1988 {
1989         rsurface.rtlight = rtlight;
1990 }
1991
1992 void R_Shadow_RenderMode_Reset(void)
1993 {
1994         R_Mesh_ResetRenderTargets();
1995         R_SetViewport(&r_refdef.view.viewport);
1996         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1997         R_Mesh_ResetTextureState();
1998         GL_DepthRange(0, 1);
1999         GL_DepthTest(true);
2000         GL_DepthMask(false);
2001         GL_DepthFunc(GL_LEQUAL);
2002         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2003         r_refdef.view.cullface_front = r_shadow_cullface_front;
2004         r_refdef.view.cullface_back = r_shadow_cullface_back;
2005         GL_CullFace(r_refdef.view.cullface_back);
2006         GL_Color(1, 1, 1, 1);
2007         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2008         GL_BlendFunc(GL_ONE, GL_ZERO);
2009         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2010         r_shadow_usingshadowmap2d = false;
2011         r_shadow_usingshadowmaportho = false;
2012         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2013 }
2014
2015 void R_Shadow_ClearStencil(void)
2016 {
2017         GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2018         r_refdef.stats.lights_clears++;
2019 }
2020
2021 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2022 {
2023         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2024         if (r_shadow_rendermode == mode)
2025                 return;
2026         R_Shadow_RenderMode_Reset();
2027         GL_DepthFunc(GL_LESS);
2028         GL_ColorMask(0, 0, 0, 0);
2029         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2030         GL_CullFace(GL_NONE);
2031         R_SetupShader_DepthOrShadow();
2032         r_shadow_rendermode = mode;
2033         switch(mode)
2034         {
2035         default:
2036                 break;
2037         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2038         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2039                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2040                 break;
2041         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2042         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2043                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2044                 break;
2045         }
2046 }
2047
2048 static void R_Shadow_MakeVSDCT(void)
2049 {
2050         // maps to a 2x3 texture rectangle with normalized coordinates
2051         // +-
2052         // XX
2053         // YY
2054         // ZZ
2055         // stores abs(dir.xy), offset.xy/2.5
2056         unsigned char data[4*6] =
2057         {
2058                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2059                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2060                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2061                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2062                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2063                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2064         };
2065         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2066 }
2067
2068 static void R_Shadow_MakeShadowMap(int side, int size)
2069 {
2070         switch (r_shadow_shadowmode)
2071         {
2072         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2073                 if (r_shadow_shadowmap2dtexture) return;
2074                 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2075                 r_shadow_shadowmap2dcolortexture = NULL;
2076                 switch(vid.renderpath)
2077                 {
2078 #ifdef SUPPORTD3D
2079                 case RENDERPATH_D3D9:
2080                         r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2081                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2082                         break;
2083 #endif
2084                 default:
2085                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2086                         break;
2087                 }
2088                 break;
2089         default:
2090                 return;
2091         }
2092
2093         // render depth into the fbo, do not render color at all
2094         // validate the fbo now
2095         if (qglDrawBuffer)
2096         {
2097                 int status;
2098                 qglDrawBuffer(GL_NONE);CHECKGLERROR
2099                 qglReadBuffer(GL_NONE);CHECKGLERROR
2100                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2101                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2102                 {
2103                         Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2104                         Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2105                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
2106                 }
2107         }
2108 }
2109
2110 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2111 {
2112         float nearclip, farclip, bias;
2113         r_viewport_t viewport;
2114         int flipped;
2115         GLuint fbo = 0;
2116         float clearcolor[4];
2117         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2118         farclip = 1.0f;
2119         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2120         r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2121         r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2122         r_shadow_shadowmapside = side;
2123         r_shadow_shadowmapsize = size;
2124
2125         r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2126         r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2127         R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2128         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2129
2130         // complex unrolled cube approach (more flexible)
2131         if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2132                 R_Shadow_MakeVSDCT();
2133         if (!r_shadow_shadowmap2dtexture)
2134                 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2135         if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2136         r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2137         r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2138         r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2139
2140         R_Mesh_ResetTextureState();
2141         R_Mesh_ResetRenderTargets();
2142         R_Shadow_RenderMode_Reset();
2143         if (fbo)
2144         {
2145                 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2146                 R_SetupShader_DepthOrShadow();
2147         }
2148         else
2149                 R_SetupShader_ShowDepth();
2150         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2151         GL_DepthMask(true);
2152         GL_DepthTest(true);
2153
2154 init_done:
2155         R_SetViewport(&viewport);
2156         flipped = (side & 1) ^ (side >> 2);
2157         r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2158         r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2159         switch(vid.renderpath)
2160         {
2161         case RENDERPATH_GL11:
2162         case RENDERPATH_GL13:
2163         case RENDERPATH_GL20:
2164         case RENDERPATH_SOFT:
2165         case RENDERPATH_GLES2:
2166                 GL_CullFace(r_refdef.view.cullface_back);
2167                 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2168                 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2169                 {
2170                         // get tightest scissor rectangle that encloses all viewports in the clear mask
2171                         int x1 = clear & 0x15 ? 0 : size;
2172                         int x2 = clear & 0x2A ? 2 * size : size;
2173                         int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2174                         int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2175                         GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2176                         GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2177                 }
2178                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2179                 break;
2180         case RENDERPATH_D3D9:
2181         case RENDERPATH_D3D10:
2182         case RENDERPATH_D3D11:
2183                 Vector4Set(clearcolor, 1,1,1,1);
2184                 // completely different meaning than in OpenGL path
2185                 r_shadow_shadowmap_parameters[1] = 0;
2186                 r_shadow_shadowmap_parameters[3] = -bias;
2187                 // we invert the cull mode because we flip the projection matrix
2188                 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2189                 GL_CullFace(r_refdef.view.cullface_front);
2190                 // D3D considers it an error to use a scissor larger than the viewport...  clear just this view
2191                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2192                 if (r_shadow_shadowmapsampler)
2193                 {
2194                         GL_ColorMask(0,0,0,0);
2195                         if (clear)
2196                                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2197                 }
2198                 else
2199                 {
2200                         GL_ColorMask(1,1,1,1);
2201                         if (clear)
2202                                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2203                 }
2204                 break;
2205         }
2206 }
2207
2208 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2209 {
2210         R_Mesh_ResetTextureState();
2211         R_Mesh_ResetRenderTargets();
2212         if (transparent)
2213         {
2214                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2215                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2216                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2217                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2218         }
2219         R_Shadow_RenderMode_Reset();
2220         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2221         if (!transparent)
2222                 GL_DepthFunc(GL_EQUAL);
2223         // do global setup needed for the chosen lighting mode
2224         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2225                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2226         r_shadow_usingshadowmap2d = shadowmapping;
2227         r_shadow_rendermode = r_shadow_lightingrendermode;
2228         // only draw light where this geometry was already rendered AND the
2229         // stencil is 128 (values other than this mean shadow)
2230         if (stenciltest)
2231                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2232         else
2233                 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2234 }
2235
2236 static const unsigned short bboxelements[36] =
2237 {
2238         5, 1, 3, 5, 3, 7,
2239         6, 2, 0, 6, 0, 4,
2240         7, 3, 2, 7, 2, 6,
2241         4, 0, 1, 4, 1, 5,
2242         4, 5, 7, 4, 7, 6,
2243         1, 0, 2, 1, 2, 3,
2244 };
2245
2246 static const float bboxpoints[8][3] =
2247 {
2248         {-1,-1,-1},
2249         { 1,-1,-1},
2250         {-1, 1,-1},
2251         { 1, 1,-1},
2252         {-1,-1, 1},
2253         { 1,-1, 1},
2254         {-1, 1, 1},
2255         { 1, 1, 1},
2256 };
2257
2258 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2259 {
2260         int i;
2261         float vertex3f[8*3];
2262         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2263 // do global setup needed for the chosen lighting mode
2264         R_Shadow_RenderMode_Reset();
2265         r_shadow_rendermode = r_shadow_lightingrendermode;
2266         R_EntityMatrix(&identitymatrix);
2267         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2268         // only draw light where this geometry was already rendered AND the
2269         // stencil is 128 (values other than this mean shadow)
2270         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2271         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2272
2273         r_shadow_usingshadowmap2d = shadowmapping;
2274
2275         // render the lighting
2276         R_SetupShader_DeferredLight(rsurface.rtlight);
2277         for (i = 0;i < 8;i++)
2278                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2279         GL_ColorMask(1,1,1,1);
2280         GL_DepthMask(false);
2281         GL_DepthRange(0, 1);
2282         GL_PolygonOffset(0, 0);
2283         GL_DepthTest(true);
2284         GL_DepthFunc(GL_GREATER);
2285         GL_CullFace(r_refdef.view.cullface_back);
2286         R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2287         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2288 }
2289
2290 static void R_Shadow_UpdateBounceGridTexture(void)
2291 {
2292 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2293         dlight_t *light;
2294         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2295         int bouncecount;
2296         int bouncelimit;
2297         int c[3];
2298         int hitsupercontentsmask;
2299         int maxbounce;
2300         int numpixels;
2301         int resolution[3];
2302         int shootparticles;
2303         int shotparticles;
2304         int tex[3];
2305         trace_t cliptrace;
2306         unsigned char *pixel;
2307         unsigned char *pixels;
2308         unsigned int lightindex;
2309         unsigned int range;
2310         unsigned int range1;
2311         unsigned int range2;
2312         unsigned int seed = (unsigned int)(realtime * 1000.0f);
2313         vec3_t shotcolor;
2314         vec3_t baseshotcolor;
2315         vec3_t clipend;
2316         vec3_t clipstart;
2317         vec3_t ispacing;
2318         vec3_t maxs;
2319         vec3_t mins;
2320         vec3_t size;
2321         vec3_t spacing;
2322         vec3_t lightcolor;
2323         vec_t radius;
2324         vec_t s;
2325         vec_t lightintensity;
2326         float m[16];
2327         qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2328         rtlight_t *rtlight;
2329         if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2330         {
2331                 if (r_shadow_bouncegridtexture)
2332                 {
2333                         R_FreeTexture(r_shadow_bouncegridtexture);
2334                         r_shadow_bouncegridtexture = NULL;
2335                 }
2336                 return;
2337         }
2338         if (r_refdef.scene.worldmodel)
2339         {
2340                 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2341                 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2342                 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2343                 VectorSubtract(maxs, mins, size);
2344                 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2345                 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2346                 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2347                 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2348                 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2349                 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2350                 spacing[0] = size[0] / resolution[0];
2351                 spacing[1] = size[1] / resolution[1];
2352                 spacing[2] = size[2] / resolution[2];
2353                 ispacing[0] = 1.0f / spacing[0];
2354                 ispacing[1] = 1.0f / spacing[1];
2355                 ispacing[2] = 1.0f / spacing[2];
2356         }
2357         else
2358         {
2359                 VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2360                 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2361                 VectorMultiply(resolution, spacing, size);
2362                 ispacing[0] = 1.0f / spacing[0];
2363                 ispacing[1] = 1.0f / spacing[1];
2364                 ispacing[2] = 1.0f / spacing[2];
2365                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2366                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2367                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2368                 VectorAdd(mins, size, maxs);
2369         }
2370         memset(m, 0, sizeof(m));
2371         m[0] = 1.0f / size[0];
2372         m[3] = -mins[0] * m[0];
2373         m[5] = 1.0f / size[1];
2374         m[7] = -mins[1] * m[5];
2375         m[10] = 1.0f / size[2];
2376         m[11] = -mins[2] * m[10];
2377         m[15] = 1.0f;
2378         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2379         r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2380         if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
2381                 return;
2382         numpixels = resolution[0]*resolution[1]*resolution[2];
2383         // allocate pixels for this update...
2384         pixels = Mem_Alloc(r_main_mempool, numpixels * sizeof(unsigned char[4]));
2385         // figure out what we want to interact with
2386         if (r_shadow_bouncegrid_hitmodels.integer)
2387                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2388         else
2389                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2390         // iterate world rtlights
2391         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2392         range1 = isstatic ? 0 : r_refdef.scene.numlights;
2393         range2 = range + range1;
2394         for (lightindex = 0;lightindex < range2;lightindex++)
2395         {
2396                 if (isstatic)
2397                 {
2398                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2399                         if (!light || !(light->flags & flag))
2400                                 continue;
2401                         rtlight = &light->rtlight;
2402                         // when static, we skip styled lights because they tend to change...
2403                         if (rtlight->style > 0)
2404                                 continue;
2405                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2406                 }
2407                 else
2408                 {
2409                         if (lightindex < range)
2410                         {
2411                                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2412                                 rtlight = &light->rtlight;
2413                         }
2414                         else
2415                                 rtlight = r_refdef.scene.lights[lightindex - range];
2416                         // draw only visible lights (major speedup)
2417                         if (!rtlight->draw)
2418                                 continue;
2419                         VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2420                 }
2421                 if (!VectorLength2(lightcolor))
2422                         continue;
2423                 // shoot particles from this light
2424                 // use a calculation for the number of particles that will not
2425                 // vary with lightstyle, otherwise we get randomized particle
2426                 // distribution, the seeded random is only consistent for a
2427                 // consistent number of particles on this light...
2428                 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2429                 s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
2430                 lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
2431                 if (lightindex >= range)
2432                         lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2433                 shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2434                 if (!shootparticles)
2435                         continue;
2436                 s = 255.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2437                 VectorScale(lightcolor, s, baseshotcolor);
2438                 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2439                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2440                 {
2441                         if (r_shadow_bouncegrid_stablerandom.integer > 0)
2442                                 seed = lightindex * 11937 + shotparticles;
2443                         VectorCopy(baseshotcolor, shotcolor);
2444                         VectorCopy(rtlight->shadoworigin, clipstart);
2445                         if (r_shadow_bouncegrid_stablerandom.integer < 0)
2446                                 VectorRandom(clipend);
2447                         else
2448                                 VectorCheeseRandom(clipend);
2449                         VectorMA(clipstart, radius, clipend, clipend);
2450                         bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2451                         for (bouncecount = 0;;bouncecount++)
2452                         {
2453                                 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2454                                 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2455                                 if (cliptrace.fraction >= 1.0f)
2456                                         break;
2457                                 if (VectorLength2(shotcolor) < 1.0f)
2458                                         break;
2459                                 if (bouncecount > 0)
2460                                 {
2461                                         // figure out which texture pixel this is in
2462                                         tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2463                                         tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2464                                         tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2465                                         if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
2466                                         {
2467                                                 // it is within bounds...
2468                                                 pixel = pixels + 4 * ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2469                                                 // add to the pixel color
2470                                                 c[0] = pixel[0] + (int)shotcolor[2];
2471                                                 c[1] = pixel[1] + (int)shotcolor[1];
2472                                                 c[2] = pixel[2] + (int)shotcolor[0];
2473                                                 pixel[0] = (unsigned char)min(c[0], 255);
2474                                                 pixel[1] = (unsigned char)min(c[1], 255);
2475                                                 pixel[2] = (unsigned char)min(c[2], 255);
2476                                                 pixel[3] = 255;
2477                                         }
2478                                 }
2479                                 if (bouncecount >= bouncelimit)
2480                                         break;
2481                                 // scale down shot color by bounce intensity and texture color
2482                                 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2483                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2484                                         VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2485                                 // reflect the remaining portion of the line across plane normal
2486                                 //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2487                                 //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2488                                 // random direction, primarily along plane normal
2489                                 s = VectorDistance(cliptrace.endpos, clipend);
2490                                 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2491                                         VectorRandom(clipend);
2492                                 else
2493                                         VectorCheeseRandom(clipend);
2494                                 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2495                                 VectorNormalize(clipend);
2496                                 VectorScale(clipend, s, clipend);
2497                                 // calculate the new line start and end
2498                                 VectorCopy(cliptrace.endpos, clipstart);
2499                                 VectorAdd(clipstart, clipend, clipend);
2500                         }
2501                 }
2502         }
2503         if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2504                 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2505         else
2506         {
2507                 VectorCopy(resolution, r_shadow_bouncegridresolution);
2508                 if (r_shadow_bouncegridtexture)
2509                         R_FreeTexture(r_shadow_bouncegridtexture);
2510                 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2511         }
2512         Mem_Free(pixels);
2513         r_shadow_bouncegridtime = realtime;
2514 }
2515
2516 #define MAXPARTICLESPERLIGHT 262144
2517 #define MAXLIGHTSPERDRAW 1024
2518
2519 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2520 {
2521         int batchcount;
2522         int i;
2523         int j;
2524         int bouncecount;
2525         int hitsupercontentsmask;
2526         int n;
2527         int shotparticles;
2528         int shootparticles = 0;
2529         int bouncelimit;
2530         int maxbounce;
2531         unsigned int seed = 0;
2532         static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2533         static float vertex3f[MAXLIGHTSPERDRAW*24];
2534         static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2535         static float color4f[MAXLIGHTSPERDRAW*32];
2536         float scaledpoints[8][3];
2537         float *v3f;
2538         float *lo4f;
2539         float *c4f;
2540         rtlight_particle_t *p;
2541         vec_t wantparticles = 0;
2542         vec_t s;
2543         vec_t radius;
2544         vec_t particlesize;
2545         vec_t iparticlesize;
2546 //      vec3_t offset;
2547 //      vec3_t right;
2548 //      vec3_t up;
2549         vec4_t org;
2550         vec4_t color;
2551         vec3_t currentcolor;
2552         vec3_t clipstart;
2553         vec3_t clipend;
2554         vec3_t shotcolor;
2555         trace_t cliptrace;
2556         if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2557                 return;
2558         if (r_shadow_particletrace.integer)
2559         {
2560                 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2561                 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2562                 wantparticles = s*s;
2563                 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2564         }
2565         else
2566                 n = 0;
2567         shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2568         if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2569         {
2570                 if (rtlight->particlecache_particles)
2571                         Mem_Free(rtlight->particlecache_particles);
2572                 rtlight->particlecache_particles = NULL;
2573                 rtlight->particlecache_numparticles = 0;
2574                 rtlight->particlecache_maxparticles = n;
2575                 rtlight->particlecache_updateparticle = 0;
2576                 if (rtlight->particlecache_maxparticles)
2577                         rtlight->particlecache_particles = Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2578                 shootparticles = n * 16;
2579         }
2580
2581         if (!rtlight->particlecache_maxparticles)
2582                 return;
2583
2584 //      if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2585 //              shootparticles = rtlight->particlecache_maxparticles;
2586
2587 //      if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2588 //              shootparticles = 0;
2589
2590         maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2591         r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2592         for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2593         {
2594                 seed = rtlight->particlecache_updateparticle;
2595                 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2596                 VectorCopy(rtlight->shadoworigin, clipstart);
2597                 VectorRandom(clipend);
2598                 VectorMA(clipstart, radius, clipend, clipend);
2599                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2600                 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2601                 for (bouncecount = 0;;bouncecount++)
2602                 {
2603                         cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2604                         //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2605                         if (cliptrace.fraction >= 1.0f)
2606                                 break;
2607                         if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2608                                 break;
2609                         if (bouncecount >= bouncelimit)
2610                         {
2611                                 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2612                                 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2613                                 rtlight->particlecache_updateparticle++;
2614                                 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2615                                         rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2616                                 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2617                                 {
2618                                         rtlight->particlecache_updateparticle = 0;
2619                                         shotparticles = shootparticles;
2620                                 }
2621                                 break;
2622                         }
2623                         // scale down shot color by bounce intensity and texture color
2624                         VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2625                         if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2626                                 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2627                         // reflect the remaining portion of the line across plane normal
2628                         //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2629                         //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2630                         // random direction, primarily along plane normal
2631                         s = VectorDistance(cliptrace.endpos, clipend);
2632                         VectorRandom(clipend);
2633                         VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2634                         VectorNormalize(clipend);
2635                         VectorScale(clipend, s, clipend);
2636                         // calculate the new line start and end
2637                         VectorCopy(cliptrace.endpos, clipstart);
2638                         VectorAdd(clipstart, clipend, clipend);
2639                 }
2640         }
2641
2642         if (!rtlight->particlecache_numparticles)
2643                 return;
2644
2645         // render the particles as deferred lights
2646 // do global setup needed for the chosen lighting mode
2647         R_Shadow_RenderMode_Reset();
2648         r_shadow_rendermode = r_shadow_lightingrendermode;
2649         r_shadow_usingshadowmap2d = false;
2650         R_EntityMatrix(&identitymatrix);
2651         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2652         // only draw light where this geometry was already rendered AND the
2653         // stencil is 128 (values other than this mean shadow)
2654         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2655         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2656         R_SetupShader_DeferredBounceLight();
2657         GL_ColorMask(1,1,1,1);
2658         GL_DepthMask(false);
2659         GL_DepthRange(0, 1);
2660         GL_PolygonOffset(0, 0);
2661         GL_DepthTest(true);
2662         GL_DepthFunc(GL_GREATER);
2663         GL_CullFace(r_refdef.view.cullface_back);
2664         s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2665         VectorScale(rtlight->currentcolor, s, currentcolor);
2666         particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2667         iparticlesize = 1.0f / particlesize;
2668 //      VectorScale(r_refdef.view.forward, particlesize, offset);
2669 //      VectorScale(r_refdef.view.left, -particlesize, right);
2670 //      VectorScale(r_refdef.view.up, particlesize, up);
2671         org[3] = iparticlesize;
2672         color[3] = 1.0f;
2673         v3f = vertex3f;
2674         lo4f = lightorigin4f;
2675         c4f = color4f;
2676         batchcount = 0;
2677         if (!bouncelight_elements[1])
2678                 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2679                         for (j = 0;j < 36;j++)
2680                                 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2681         for (j = 0;j < 8;j++)
2682                 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2683         r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2684         for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2685         {
2686                 VectorCopy(p->origin, org);
2687                 // org[3] is set above
2688                 VectorMultiply(p->color, currentcolor, color);
2689                 // color[3] is set above
2690                 VectorAdd(scaledpoints[0], org, v3f +  0);
2691                 VectorAdd(scaledpoints[1], org, v3f +  3);
2692                 VectorAdd(scaledpoints[2], org, v3f +  6);
2693                 VectorAdd(scaledpoints[3], org, v3f +  9);
2694                 VectorAdd(scaledpoints[4], org, v3f + 12);
2695                 VectorAdd(scaledpoints[5], org, v3f + 15);
2696                 VectorAdd(scaledpoints[6], org, v3f + 18);
2697                 VectorAdd(scaledpoints[7], org, v3f + 21);
2698                 Vector4Copy(org, lo4f +  0);
2699                 Vector4Copy(org, lo4f +  4);
2700                 Vector4Copy(org, lo4f +  8);
2701                 Vector4Copy(org, lo4f + 12);
2702                 Vector4Copy(org, lo4f + 16);
2703                 Vector4Copy(org, lo4f + 20);
2704                 Vector4Copy(org, lo4f + 24);
2705                 Vector4Copy(org, lo4f + 28);
2706                 Vector4Copy(color, c4f + 0);
2707                 Vector4Copy(color, c4f + 4);
2708                 Vector4Copy(color, c4f + 8);
2709                 Vector4Copy(color, c4f + 12);
2710                 Vector4Copy(color, c4f + 16);
2711                 Vector4Copy(color, c4f + 20);
2712                 Vector4Copy(color, c4f + 24);
2713                 Vector4Copy(color, c4f + 28);
2714                 v3f += 24;
2715                 lo4f += 32;
2716                 c4f += 32;
2717                 batchcount++;
2718                 if (batchcount >= MAXLIGHTSPERDRAW)
2719                 {
2720                         r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2721                         R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2722                         R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2723                         v3f = vertex3f;
2724                         lo4f = lightorigin4f;
2725                         c4f = color4f;
2726                         batchcount = 0;
2727                 }
2728         }
2729         if (batchcount)
2730         {
2731                 r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2732                 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2733                 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2734                 v3f = vertex3f;
2735                 lo4f = lightorigin4f;
2736                 c4f = color4f;
2737                 batchcount = 0;
2738         }
2739 }
2740
2741 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2742 {
2743         R_Shadow_RenderMode_Reset();
2744         GL_BlendFunc(GL_ONE, GL_ONE);
2745         GL_DepthRange(0, 1);
2746         GL_DepthTest(r_showshadowvolumes.integer < 2);
2747         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2748         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2749         GL_CullFace(GL_NONE);
2750         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2751 }
2752
2753 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2754 {
2755         R_Shadow_RenderMode_Reset();
2756         GL_BlendFunc(GL_ONE, GL_ONE);
2757         GL_DepthRange(0, 1);
2758         GL_DepthTest(r_showlighting.integer < 2);
2759         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2760         if (!transparent)
2761                 GL_DepthFunc(GL_EQUAL);
2762         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2763         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2764 }
2765
2766 void R_Shadow_RenderMode_End(void)
2767 {
2768         R_Shadow_RenderMode_Reset();
2769         R_Shadow_RenderMode_ActiveLight(NULL);
2770         GL_DepthMask(true);
2771         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2772         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2773 }
2774
2775 int bboxedges[12][2] =
2776 {
2777         // top
2778         {0, 1}, // +X
2779         {0, 2}, // +Y
2780         {1, 3}, // Y, +X
2781         {2, 3}, // X, +Y
2782         // bottom
2783         {4, 5}, // +X
2784         {4, 6}, // +Y
2785         {5, 7}, // Y, +X
2786         {6, 7}, // X, +Y
2787         // verticals
2788         {0, 4}, // +Z
2789         {1, 5}, // X, +Z
2790         {2, 6}, // Y, +Z
2791         {3, 7}, // XY, +Z
2792 };
2793
2794 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2795 {
2796         if (!r_shadow_scissor.integer)
2797         {
2798                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2799                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2800                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2801                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2802                 return false;
2803         }
2804         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2805                 return true; // invisible
2806         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2807         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2808         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2809         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2810                 r_refdef.stats.lights_scissored++;
2811         return false;
2812 }
2813
2814 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2815 {
2816         int i;
2817         const float *vertex3f;
2818         const float *normal3f;
2819         float *color4f;
2820         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2821         switch (r_shadow_rendermode)
2822         {
2823         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2824         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2825                 if (VectorLength2(diffusecolor) > 0)
2826                 {
2827                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2828                         {
2829                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2830                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2831                                 if ((dot = DotProduct(n, v)) < 0)
2832                                 {
2833                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2834                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2835                                 }
2836                                 else
2837                                         VectorCopy(ambientcolor, color4f);
2838                                 if (r_refdef.fogenabled)
2839                                 {
2840                                         float f;
2841                                         f = RSurf_FogVertex(vertex3f);
2842                                         VectorScale(color4f, f, color4f);
2843                                 }
2844                                 color4f[3] = 1;
2845                         }
2846                 }
2847                 else
2848                 {
2849                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2850                         {
2851                                 VectorCopy(ambientcolor, color4f);
2852                                 if (r_refdef.fogenabled)
2853                                 {
2854                                         float f;
2855                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2856                                         f = RSurf_FogVertex(vertex3f);
2857                                         VectorScale(color4f + 4*i, f, color4f);
2858                                 }
2859                                 color4f[3] = 1;
2860                         }
2861                 }
2862                 break;
2863         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2864                 if (VectorLength2(diffusecolor) > 0)
2865                 {
2866                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2867                         {
2868                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2869                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2870                                 {
2871                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2872                                         if ((dot = DotProduct(n, v)) < 0)
2873                                         {
2874                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2875                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2876                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2877                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2878                                         }
2879                                         else
2880                                         {
2881                                                 color4f[0] = ambientcolor[0] * distintensity;
2882                                                 color4f[1] = ambientcolor[1] * distintensity;
2883                                                 color4f[2] = ambientcolor[2] * distintensity;
2884                                         }
2885                                         if (r_refdef.fogenabled)
2886                                         {
2887                                                 float f;
2888                                                 f = RSurf_FogVertex(vertex3f);
2889                                                 VectorScale(color4f, f, color4f);
2890                                         }
2891                                 }
2892                                 else
2893                                         VectorClear(color4f);
2894                                 color4f[3] = 1;
2895                         }
2896                 }
2897                 else
2898                 {
2899                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2900                         {
2901                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2902                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2903                                 {
2904                                         color4f[0] = ambientcolor[0] * distintensity;
2905                                         color4f[1] = ambientcolor[1] * distintensity;
2906                                         color4f[2] = ambientcolor[2] * distintensity;
2907                                         if (r_refdef.fogenabled)
2908                                         {
2909                                                 float f;
2910                                                 f = RSurf_FogVertex(vertex3f);
2911                                                 VectorScale(color4f, f, color4f);
2912                                         }
2913                                 }
2914                                 else
2915                                         VectorClear(color4f);
2916                                 color4f[3] = 1;
2917                         }
2918                 }
2919                 break;
2920         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2921                 if (VectorLength2(diffusecolor) > 0)
2922                 {
2923                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2924                         {
2925                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2926                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2927                                 {
2928                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2929                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2930                                         if ((dot = DotProduct(n, v)) < 0)
2931                                         {
2932                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2933                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2934                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2935                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2936                                         }
2937                                         else
2938                                         {
2939                                                 color4f[0] = ambientcolor[0] * distintensity;
2940                                                 color4f[1] = ambientcolor[1] * distintensity;
2941                                                 color4f[2] = ambientcolor[2] * distintensity;
2942                                         }
2943                                         if (r_refdef.fogenabled)
2944                                         {
2945                                                 float f;
2946                                                 f = RSurf_FogVertex(vertex3f);
2947                                                 VectorScale(color4f, f, color4f);
2948                                         }
2949                                 }
2950                                 else
2951                                         VectorClear(color4f);
2952                                 color4f[3] = 1;
2953                         }
2954                 }
2955                 else
2956                 {
2957                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2958                         {
2959                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2960                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2961                                 {
2962                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2963                                         color4f[0] = ambientcolor[0] * distintensity;
2964                                         color4f[1] = ambientcolor[1] * distintensity;
2965                                         color4f[2] = ambientcolor[2] * distintensity;
2966                                         if (r_refdef.fogenabled)
2967                                         {
2968                                                 float f;
2969                                                 f = RSurf_FogVertex(vertex3f);
2970                                                 VectorScale(color4f, f, color4f);
2971                                         }
2972                                 }
2973                                 else
2974                                         VectorClear(color4f);
2975                                 color4f[3] = 1;
2976                         }
2977                 }
2978                 break;
2979         default:
2980                 break;
2981         }
2982 }
2983
2984 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2985 {
2986         // used to display how many times a surface is lit for level design purposes
2987         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2988         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2989         RSurf_DrawBatch();
2990 }
2991
2992 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2993 {
2994         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2995         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2996         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2997                 GL_DepthFunc(GL_EQUAL);
2998         RSurf_DrawBatch();
2999         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3000                 GL_DepthFunc(GL_LEQUAL);
3001 }
3002
3003 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3004 {
3005         int renders;
3006         int i;
3007         int stop;
3008         int newfirstvertex;
3009         int newlastvertex;
3010         int newnumtriangles;
3011         int *newe;
3012         const int *e;
3013         float *c;
3014         int maxtriangles = 4096;
3015         static int newelements[4096*3];
3016         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3017         for (renders = 0;renders < 4;renders++)
3018         {
3019                 stop = true;
3020                 newfirstvertex = 0;
3021                 newlastvertex = 0;
3022                 newnumtriangles = 0;
3023                 newe = newelements;
3024                 // due to low fillrate on the cards this vertex lighting path is
3025                 // designed for, we manually cull all triangles that do not
3026                 // contain a lit vertex
3027                 // this builds batches of triangles from multiple surfaces and
3028                 // renders them at once
3029                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3030                 {
3031                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3032                         {
3033                                 if (newnumtriangles)
3034                                 {
3035                                         newfirstvertex = min(newfirstvertex, e[0]);
3036                                         newlastvertex  = max(newlastvertex, e[0]);
3037                                 }
3038                                 else
3039                                 {
3040                                         newfirstvertex = e[0];
3041                                         newlastvertex = e[0];
3042                                 }
3043                                 newfirstvertex = min(newfirstvertex, e[1]);
3044                                 newlastvertex  = max(newlastvertex, e[1]);
3045                                 newfirstvertex = min(newfirstvertex, e[2]);
3046                                 newlastvertex  = max(newlastvertex, e[2]);
3047                                 newe[0] = e[0];
3048                                 newe[1] = e[1];
3049                                 newe[2] = e[2];
3050                                 newnumtriangles++;
3051                                 newe += 3;
3052                                 if (newnumtriangles >= maxtriangles)
3053                                 {
3054                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3055                                         newnumtriangles = 0;
3056                                         newe = newelements;
3057                                         stop = false;
3058                                 }
3059                         }
3060                 }
3061                 if (newnumtriangles >= 1)
3062                 {
3063                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3064                         stop = false;
3065                 }
3066                 // if we couldn't find any lit triangles, exit early
3067                 if (stop)
3068                         break;
3069                 // now reduce the intensity for the next overbright pass
3070                 // we have to clamp to 0 here incase the drivers have improper
3071                 // handling of negative colors
3072                 // (some old drivers even have improper handling of >1 color)
3073                 stop = true;
3074                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3075                 {
3076                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3077                         {
3078                                 c[0] = max(0, c[0] - 1);
3079                                 c[1] = max(0, c[1] - 1);
3080                                 c[2] = max(0, c[2] - 1);
3081                                 stop = false;
3082                         }
3083                         else
3084                                 VectorClear(c);
3085                 }
3086                 // another check...
3087                 if (stop)
3088                         break;
3089         }
3090 }
3091
3092 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3093 {
3094         // OpenGL 1.1 path (anything)
3095         float ambientcolorbase[3], diffusecolorbase[3];
3096         float ambientcolorpants[3], diffusecolorpants[3];
3097         float ambientcolorshirt[3], diffusecolorshirt[3];
3098         const float *surfacecolor = rsurface.texture->dlightcolor;
3099         const float *surfacepants = rsurface.colormap_pantscolor;
3100         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3101         rtexture_t *basetexture = rsurface.texture->basetexture;
3102         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3103         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3104         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3105         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3106         ambientscale *= 2 * r_refdef.view.colorscale;
3107         diffusescale *= 2 * r_refdef.view.colorscale;
3108         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3109         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3110         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3111         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3112         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3113         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3114         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3115         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3116         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3117         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3118         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3119         R_Mesh_TexBind(0, basetexture);
3120         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3121         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3122         switch(r_shadow_rendermode)
3123         {
3124         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3125                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3126                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3127                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3128                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3129                 break;
3130         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3131                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3132                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3133                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3134                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3135                 // fall through
3136         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3137                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3138                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3139                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3140                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3141                 break;
3142         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3143                 break;
3144         default:
3145                 break;
3146         }
3147         //R_Mesh_TexBind(0, basetexture);
3148         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3149         if (dopants)
3150         {
3151                 R_Mesh_TexBind(0, pantstexture);
3152                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3153         }
3154         if (doshirt)
3155         {
3156                 R_Mesh_TexBind(0, shirttexture);
3157                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3158         }
3159 }
3160
3161 extern cvar_t gl_lightmaps;
3162 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3163 {
3164         float ambientscale, diffusescale, specularscale;
3165         qboolean negated;
3166         float lightcolor[3];
3167         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3168         ambientscale = rsurface.rtlight->ambientscale;
3169         diffusescale = rsurface.rtlight->diffusescale;
3170         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3171         if (!r_shadow_usenormalmap.integer)
3172         {
3173                 ambientscale += 1.0f * diffusescale;
3174                 diffusescale = 0;
3175                 specularscale = 0;
3176         }
3177         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3178                 return;
3179         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3180         if(negated)
3181         {
3182                 VectorNegate(lightcolor, lightcolor);
3183                 switch(vid.renderpath)
3184                 {
3185                 case RENDERPATH_GL11:
3186                 case RENDERPATH_GL13:
3187                 case RENDERPATH_GL20:
3188                 case RENDERPATH_GLES2:
3189                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3190                         break;
3191                 case RENDERPATH_D3D9:
3192 #ifdef SUPPORTD3D
3193                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3194 #endif
3195                         break;
3196                 case RENDERPATH_D3D10:
3197                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3198                         break;
3199                 case RENDERPATH_D3D11:
3200                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3201                         break;
3202                 case RENDERPATH_SOFT:
3203                         DPSOFTRAST_BlendSubtract(true);
3204                         break;
3205                 }
3206         }
3207         RSurf_SetupDepthAndCulling();
3208         switch (r_shadow_rendermode)
3209         {
3210         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3211                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3212                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3213                 break;
3214         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3215                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3216                 break;
3217         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3218         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3219         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3220         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3221                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3222                 break;
3223         default:
3224                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3225                 break;
3226         }
3227         if(negated)
3228         {
3229                 switch(vid.renderpath)
3230                 {
3231                 case RENDERPATH_GL11:
3232                 case RENDERPATH_GL13:
3233                 case RENDERPATH_GL20:
3234                 case RENDERPATH_GLES2:
3235                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3236                         break;
3237                 case RENDERPATH_D3D9:
3238 #ifdef SUPPORTD3D
3239                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3240 #endif
3241                         break;
3242                 case RENDERPATH_D3D10:
3243                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3244                         break;
3245                 case RENDERPATH_D3D11:
3246                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3247                         break;
3248                 case RENDERPATH_SOFT:
3249                         DPSOFTRAST_BlendSubtract(false);
3250                         break;
3251                 }
3252         }
3253 }
3254
3255 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)
3256 {
3257         matrix4x4_t tempmatrix = *matrix;
3258         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3259
3260         // if this light has been compiled before, free the associated data
3261         R_RTLight_Uncompile(rtlight);
3262
3263         // clear it completely to avoid any lingering data
3264         memset(rtlight, 0, sizeof(*rtlight));
3265
3266         // copy the properties
3267         rtlight->matrix_lighttoworld = tempmatrix;
3268         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3269         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3270         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3271         VectorCopy(color, rtlight->color);
3272         rtlight->cubemapname[0] = 0;
3273         if (cubemapname && cubemapname[0])
3274                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3275         rtlight->shadow = shadow;
3276         rtlight->corona = corona;
3277         rtlight->style = style;
3278         rtlight->isstatic = isstatic;
3279         rtlight->coronasizescale = coronasizescale;
3280         rtlight->ambientscale = ambientscale;
3281         rtlight->diffusescale = diffusescale;
3282         rtlight->specularscale = specularscale;
3283         rtlight->flags = flags;
3284
3285         // compute derived data
3286         //rtlight->cullradius = rtlight->radius;
3287         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3288         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3289         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3290         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3291         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3292         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3293         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3294 }
3295
3296 // compiles rtlight geometry
3297 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3298 void R_RTLight_Compile(rtlight_t *rtlight)
3299 {
3300         int i;
3301         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3302         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3303         entity_render_t *ent = r_refdef.scene.worldentity;
3304         dp_model_t *model = r_refdef.scene.worldmodel;
3305         unsigned char *data;
3306         shadowmesh_t *mesh;
3307
3308         // compile the light
3309         rtlight->compiled = true;
3310         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3311         rtlight->static_numleafs = 0;
3312         rtlight->static_numleafpvsbytes = 0;
3313         rtlight->static_leaflist = NULL;
3314         rtlight->static_leafpvs = NULL;
3315         rtlight->static_numsurfaces = 0;
3316         rtlight->static_surfacelist = NULL;
3317         rtlight->static_shadowmap_receivers = 0x3F;
3318         rtlight->static_shadowmap_casters = 0x3F;
3319         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3320         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3321         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3322         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3323         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3324         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3325
3326         if (model && model->GetLightInfo)
3327         {
3328                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3329                 r_shadow_compilingrtlight = rtlight;
3330                 R_FrameData_SetMark();
3331                 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, 0, NULL);
3332                 R_FrameData_ReturnToMark();
3333                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3334                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3335                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3336                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3337                 rtlight->static_numsurfaces = numsurfaces;
3338                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3339                 rtlight->static_numleafs = numleafs;
3340                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3341                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3342                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3343                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3344                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3345                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3346                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3347                 if (rtlight->static_numsurfaces)
3348                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3349                 if (rtlight->static_numleafs)
3350                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3351                 if (rtlight->static_numleafpvsbytes)
3352                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3353                 if (rtlight->static_numshadowtrispvsbytes)
3354                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3355                 if (rtlight->static_numlighttrispvsbytes)
3356                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3357                 R_FrameData_SetMark();
3358                 switch (rtlight->shadowmode)
3359                 {
3360                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3361                         if (model->CompileShadowMap && rtlight->shadow)
3362                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3363                         break;
3364                 default:
3365                         if (model->CompileShadowVolume && rtlight->shadow)
3366                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3367                         break;
3368                 }
3369                 R_FrameData_ReturnToMark();
3370                 // now we're done compiling the rtlight
3371                 r_shadow_compilingrtlight = NULL;
3372         }
3373
3374
3375         // use smallest available cullradius - box radius or light radius
3376         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3377         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3378
3379         shadowzpasstris = 0;
3380         if (rtlight->static_meshchain_shadow_zpass)
3381                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3382                         shadowzpasstris += mesh->numtriangles;
3383
3384         shadowzfailtris = 0;
3385         if (rtlight->static_meshchain_shadow_zfail)
3386                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3387                         shadowzfailtris += mesh->numtriangles;
3388
3389         lighttris = 0;
3390         if (rtlight->static_numlighttrispvsbytes)
3391                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3392                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3393                                 lighttris++;
3394
3395         shadowtris = 0;
3396         if (rtlight->static_numlighttrispvsbytes)
3397                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3398                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3399                                 shadowtris++;
3400
3401         if (developer_extra.integer)
3402                 Con_DPrintf("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);
3403 }
3404
3405 void R_RTLight_Uncompile(rtlight_t *rtlight)
3406 {
3407         if (rtlight->compiled)
3408         {
3409                 if (rtlight->static_meshchain_shadow_zpass)
3410                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3411                 rtlight->static_meshchain_shadow_zpass = NULL;
3412                 if (rtlight->static_meshchain_shadow_zfail)
3413                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3414                 rtlight->static_meshchain_shadow_zfail = NULL;
3415                 if (rtlight->static_meshchain_shadow_shadowmap)
3416                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3417                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3418                 // these allocations are grouped
3419                 if (rtlight->static_surfacelist)
3420                         Mem_Free(rtlight->static_surfacelist);
3421                 rtlight->static_numleafs = 0;
3422                 rtlight->static_numleafpvsbytes = 0;
3423                 rtlight->static_leaflist = NULL;
3424                 rtlight->static_leafpvs = NULL;
3425                 rtlight->static_numsurfaces = 0;
3426                 rtlight->static_surfacelist = NULL;
3427                 rtlight->static_numshadowtrispvsbytes = 0;
3428                 rtlight->static_shadowtrispvs = NULL;
3429                 rtlight->static_numlighttrispvsbytes = 0;
3430                 rtlight->static_lighttrispvs = NULL;
3431                 rtlight->compiled = false;
3432         }
3433 }
3434
3435 void R_Shadow_UncompileWorldLights(void)
3436 {
3437         size_t lightindex;
3438         dlight_t *light;
3439         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3440         for (lightindex = 0;lightindex < range;lightindex++)
3441         {
3442                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3443                 if (!light)
3444                         continue;
3445                 R_RTLight_Uncompile(&light->rtlight);
3446         }
3447 }
3448
3449 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3450 {
3451         int i, j;
3452         mplane_t plane;
3453         // reset the count of frustum planes
3454         // see rtlight->cached_frustumplanes definition for how much this array
3455         // can hold
3456         rtlight->cached_numfrustumplanes = 0;
3457
3458         // haven't implemented a culling path for ortho rendering
3459         if (!r_refdef.view.useperspective)
3460         {
3461                 // check if the light is on screen and copy the 4 planes if it is
3462                 for (i = 0;i < 4;i++)
3463                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3464                                 break;
3465                 if (i == 4)
3466                         for (i = 0;i < 4;i++)
3467                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3468                 return;
3469         }
3470
3471 #if 1
3472         // generate a deformed frustum that includes the light origin, this is
3473         // used to cull shadow casting surfaces that can not possibly cast a
3474         // shadow onto the visible light-receiving surfaces, which can be a
3475         // performance gain
3476         //
3477         // if the light origin is onscreen the result will be 4 planes exactly
3478         // if the light origin is offscreen on only one axis the result will
3479         // be exactly 5 planes (split-side case)
3480         // if the light origin is offscreen on two axes the result will be
3481         // exactly 4 planes (stretched corner case)
3482         for (i = 0;i < 4;i++)
3483         {
3484                 // quickly reject standard frustum planes that put the light
3485                 // origin outside the frustum
3486                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3487                         continue;
3488                 // copy the plane
3489                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3490         }
3491         // if all the standard frustum planes were accepted, the light is onscreen
3492         // otherwise we need to generate some more planes below...
3493         if (rtlight->cached_numfrustumplanes < 4)
3494         {
3495                 // at least one of the stock frustum planes failed, so we need to
3496                 // create one or two custom planes to enclose the light origin
3497                 for (i = 0;i < 4;i++)
3498                 {
3499                         // create a plane using the view origin and light origin, and a
3500                         // single point from the frustum corner set
3501                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3502                         VectorNormalize(plane.normal);
3503                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3504                         // see if this plane is backwards and flip it if so
3505                         for (j = 0;j < 4;j++)
3506                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3507                                         break;
3508                         if (j < 4)
3509                         {
3510                                 VectorNegate(plane.normal, plane.normal);
3511                                 plane.dist *= -1;
3512                                 // flipped plane, test again to see if it is now valid
3513                                 for (j = 0;j < 4;j++)
3514                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3515                                                 break;
3516                                 // if the plane is still not valid, then it is dividing the
3517                                 // frustum and has to be rejected
3518                                 if (j < 4)
3519                                         continue;
3520                         }
3521                         // we have created a valid plane, compute extra info
3522                         PlaneClassify(&plane);
3523                         // copy the plane
3524                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3525 #if 1
3526                         // if we've found 5 frustum planes then we have constructed a
3527                         // proper split-side case and do not need to keep searching for
3528                         // planes to enclose the light origin
3529                         if (rtlight->cached_numfrustumplanes == 5)
3530                                 break;
3531 #endif
3532                 }
3533         }
3534 #endif
3535
3536 #if 0
3537         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3538         {
3539                 plane = rtlight->cached_frustumplanes[i];
3540                 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));
3541         }
3542 #endif
3543
3544 #if 0
3545         // now add the light-space box planes if the light box is rotated, as any
3546         // caster outside the oriented light box is irrelevant (even if it passed
3547         // the worldspace light box, which is axial)
3548         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3549         {
3550                 for (i = 0;i < 6;i++)
3551                 {
3552                         vec3_t v;
3553                         VectorClear(v);
3554                         v[i >> 1] = (i & 1) ? -1 : 1;
3555                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3556                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3557                         plane.dist = VectorNormalizeLength(plane.normal);
3558                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3559                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3560                 }
3561         }
3562 #endif
3563
3564 #if 0
3565         // add the world-space reduced box planes
3566         for (i = 0;i < 6;i++)
3567         {
3568                 VectorClear(plane.normal);
3569                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3570                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3571                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3572         }
3573 #endif
3574
3575 #if 0
3576         {
3577         int j, oldnum;
3578         vec3_t points[8];
3579         vec_t bestdist;
3580         // reduce all plane distances to tightly fit the rtlight cull box, which
3581         // is in worldspace
3582         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3583         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3584         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3585         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3586         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3587         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3588         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3589         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3590         oldnum = rtlight->cached_numfrustumplanes;
3591         rtlight->cached_numfrustumplanes = 0;
3592         for (j = 0;j < oldnum;j++)
3593         {
3594                 // find the nearest point on the box to this plane
3595                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3596                 for (i = 1;i < 8;i++)
3597                 {
3598                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3599                         if (bestdist > dist)
3600                                 bestdist = dist;
3601                 }
3602                 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
3603                 // if the nearest point is near or behind the plane, we want this
3604                 // plane, otherwise the plane is useless as it won't cull anything
3605                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3606                 {
3607                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3608                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3609                 }
3610         }
3611         }
3612 #endif
3613 }
3614
3615 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3616 {
3617         shadowmesh_t *mesh;
3618
3619         RSurf_ActiveWorldEntity();
3620
3621         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3622         {
3623                 CHECKGLERROR
3624                 GL_CullFace(GL_NONE);
3625                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3626                 for (;mesh;mesh = mesh->next)
3627                 {
3628                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3629                                 continue;
3630                         r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3631                         if (mesh->vertex3fbuffer)
3632                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3633                         else
3634                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3635                         R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3636                 }
3637                 CHECKGLERROR
3638         }
3639         else if (r_refdef.scene.worldentity->model)
3640                 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3641
3642         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3643 }
3644
3645 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3646 {
3647         qboolean zpass = false;
3648         shadowmesh_t *mesh;
3649         int t, tend;
3650         int surfacelistindex;
3651         msurface_t *surface;
3652
3653         // if triangle neighbors are disabled, shadowvolumes are disabled
3654         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3655                 return;
3656
3657         RSurf_ActiveWorldEntity();
3658
3659         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3660         {
3661                 CHECKGLERROR
3662                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3663                 {
3664                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3665                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3666                 }
3667                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3668                 for (;mesh;mesh = mesh->next)
3669                 {
3670                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3671                         if (mesh->vertex3fbuffer)
3672                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3673                         else
3674                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3675                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3676                         {
3677                                 // increment stencil if frontface is infront of depthbuffer
3678                                 GL_CullFace(r_refdef.view.cullface_back);
3679                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3680                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3681                                 // decrement stencil if backface is infront of depthbuffer
3682                                 GL_CullFace(r_refdef.view.cullface_front);
3683                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3684                         }
3685                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3686                         {
3687                                 // decrement stencil if backface is behind depthbuffer
3688                                 GL_CullFace(r_refdef.view.cullface_front);
3689                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3690                                 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3691                                 // increment stencil if frontface is behind depthbuffer
3692                                 GL_CullFace(r_refdef.view.cullface_back);
3693                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3694                         }
3695                         R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3696                 }
3697                 CHECKGLERROR
3698         }
3699         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3700         {
3701                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3702                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3703                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3704                 {
3705                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3706                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3707                                 if (CHECKPVSBIT(trispvs, t))
3708                                         shadowmarklist[numshadowmark++] = t;
3709                 }
3710                 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);
3711         }
3712         else if (numsurfaces)
3713         {
3714                 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3715         }
3716
3717         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3718 }
3719
3720 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3721 {
3722         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3723         vec_t relativeshadowradius;
3724         RSurf_ActiveModelEntity(ent, false, false, false);
3725         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3726         // we need to re-init the shader for each entity because the matrix changed
3727         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3728         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3729         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3730         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3731         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3732         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3733         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3734         switch (r_shadow_rendermode)
3735         {
3736         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3737                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3738                 break;
3739         default:
3740                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3741                 break;
3742         }
3743         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3744 }
3745
3746 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3747 {
3748         // set up properties for rendering light onto this entity
3749         RSurf_ActiveModelEntity(ent, true, true, false);
3750         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3751         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3752         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3753         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3754 }
3755
3756 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3757 {
3758         if (!r_refdef.scene.worldmodel->DrawLight)
3759                 return;
3760
3761         // set up properties for rendering light onto this entity
3762         RSurf_ActiveWorldEntity();
3763         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3764         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3765         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3766         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3767
3768         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3769
3770         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3771 }
3772
3773 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3774 {
3775         dp_model_t *model = ent->model;
3776         if (!model->DrawLight)
3777                 return;
3778
3779         R_Shadow_SetupEntityLight(ent);
3780
3781         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3782
3783         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3784 }
3785
3786 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3787 {
3788         int i;
3789         float f;
3790         int numleafs, numsurfaces;
3791         int *leaflist, *surfacelist;
3792         unsigned char *leafpvs;
3793         unsigned char *shadowtrispvs;
3794         unsigned char *lighttrispvs;
3795         //unsigned char *surfacesides;
3796         int numlightentities;
3797         int numlightentities_noselfshadow;
3798         int numshadowentities;
3799         int numshadowentities_noselfshadow;
3800         static entity_render_t *lightentities[MAX_EDICTS];
3801         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3802         static entity_render_t *shadowentities[MAX_EDICTS];
3803         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3804         qboolean nolight;
3805
3806         rtlight->draw = false;
3807
3808         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3809         // skip lights that are basically invisible (color 0 0 0)
3810         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3811
3812         // loading is done before visibility checks because loading should happen
3813         // all at once at the start of a level, not when it stalls gameplay.
3814         // (especially important to benchmarks)
3815         // compile light
3816         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3817         {
3818                 if (rtlight->compiled)
3819                         R_RTLight_Uncompile(rtlight);
3820                 R_RTLight_Compile(rtlight);
3821         }
3822
3823         // load cubemap
3824         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3825
3826         // look up the light style value at this time
3827         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3828         VectorScale(rtlight->color, f, rtlight->currentcolor);
3829         /*
3830         if (rtlight->selected)
3831         {
3832                 f = 2 + sin(realtime * M_PI * 4.0);
3833                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3834         }
3835         */
3836
3837         // if lightstyle is currently off, don't draw the light
3838         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3839                 return;
3840
3841         // skip processing on corona-only lights
3842         if (nolight)
3843                 return;
3844
3845         // if the light box is offscreen, skip it
3846         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3847                 return;
3848
3849         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3850         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3851
3852         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3853
3854         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3855         {
3856                 // compiled light, world available and can receive realtime lighting
3857                 // retrieve leaf information
3858                 numleafs = rtlight->static_numleafs;
3859                 leaflist = rtlight->static_leaflist;
3860                 leafpvs = rtlight->static_leafpvs;
3861                 numsurfaces = rtlight->static_numsurfaces;
3862                 surfacelist = rtlight->static_surfacelist;
3863                 //surfacesides = NULL;
3864                 shadowtrispvs = rtlight->static_shadowtrispvs;
3865                 lighttrispvs = rtlight->static_lighttrispvs;
3866         }
3867         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3868         {
3869                 // dynamic light, world available and can receive realtime lighting
3870                 // calculate lit surfaces and leafs
3871                 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_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, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes);
3872                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3873                 leaflist = r_shadow_buffer_leaflist;
3874                 leafpvs = r_shadow_buffer_leafpvs;
3875                 surfacelist = r_shadow_buffer_surfacelist;
3876                 //surfacesides = r_shadow_buffer_surfacesides;
3877                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3878                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3879                 // if the reduced leaf bounds are offscreen, skip it
3880                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3881                         return;
3882         }
3883         else
3884         {
3885                 // no world
3886                 numleafs = 0;
3887                 leaflist = NULL;
3888                 leafpvs = NULL;
3889                 numsurfaces = 0;
3890                 surfacelist = NULL;
3891                 //surfacesides = NULL;
3892                 shadowtrispvs = NULL;
3893                 lighttrispvs = NULL;
3894         }
3895         // check if light is illuminating any visible leafs
3896         if (numleafs)
3897         {
3898                 for (i = 0;i < numleafs;i++)
3899                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3900                                 break;
3901                 if (i == numleafs)
3902                         return;
3903         }
3904
3905         // make a list of lit entities and shadow casting entities
3906         numlightentities = 0;
3907         numlightentities_noselfshadow = 0;
3908         numshadowentities = 0;
3909         numshadowentities_noselfshadow = 0;
3910
3911         // add dynamic entities that are lit by the light
3912         for (i = 0;i < r_refdef.scene.numentities;i++)
3913         {
3914                 dp_model_t *model;
3915                 entity_render_t *ent = r_refdef.scene.entities[i];
3916                 vec3_t org;
3917                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3918                         continue;
3919                 // skip the object entirely if it is not within the valid
3920                 // shadow-casting region (which includes the lit region)
3921                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3922                         continue;
3923                 if (!(model = ent->model))
3924                         continue;
3925                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3926                 {
3927                         // this entity wants to receive light, is visible, and is
3928                         // inside the light box
3929                         // TODO: check if the surfaces in the model can receive light
3930                         // so now check if it's in a leaf seen by the light
3931                         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))
3932                                 continue;
3933                         if (ent->flags & RENDER_NOSELFSHADOW)
3934                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3935                         else
3936                                 lightentities[numlightentities++] = ent;
3937                         // since it is lit, it probably also casts a shadow...
3938                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3939                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3940                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3941                         {
3942                                 // note: exterior models without the RENDER_NOSELFSHADOW
3943                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3944                                 // are lit normally, this means that they are
3945                                 // self-shadowing but do not shadow other
3946                                 // RENDER_NOSELFSHADOW entities such as the gun
3947                                 // (very weird, but keeps the player shadow off the gun)
3948                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3949                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3950                                 else
3951                                         shadowentities[numshadowentities++] = ent;
3952                         }
3953                 }
3954                 else if (ent->flags & RENDER_SHADOW)
3955                 {
3956                         // this entity is not receiving light, but may still need to
3957                         // cast a shadow...
3958                         // TODO: check if the surfaces in the model can cast shadow
3959                         // now check if it is in a leaf seen by the light
3960                         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))
3961                                 continue;
3962                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3963                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3964                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3965                         {
3966                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3967                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3968                                 else
3969                                         shadowentities[numshadowentities++] = ent;
3970                         }
3971                 }
3972         }
3973
3974         // return if there's nothing at all to light
3975         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3976                 return;
3977
3978         // count this light in the r_speeds
3979         r_refdef.stats.lights++;
3980
3981         // flag it as worth drawing later
3982         rtlight->draw = true;
3983
3984         // cache all the animated entities that cast a shadow but are not visible
3985         for (i = 0;i < numshadowentities;i++)
3986                 if (!shadowentities[i]->animcache_vertex3f)
3987                         R_AnimCache_GetEntity(shadowentities[i], false, false);
3988         for (i = 0;i < numshadowentities_noselfshadow;i++)
3989                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3990                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3991
3992         // allocate some temporary memory for rendering this light later in the frame
3993         // reusable buffers need to be copied, static data can be used as-is
3994         rtlight->cached_numlightentities               = numlightentities;
3995         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3996         rtlight->cached_numshadowentities              = numshadowentities;
3997         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3998         rtlight->cached_numsurfaces                    = numsurfaces;
3999         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4000         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4001         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4002         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4003         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4004         {
4005                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4006                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4007                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4008                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4009                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4010         }
4011         else
4012         {
4013                 // compiled light data
4014                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4015                 rtlight->cached_lighttrispvs = lighttrispvs;
4016                 rtlight->cached_surfacelist = surfacelist;
4017         }
4018 }
4019
4020 void R_Shadow_DrawLight(rtlight_t *rtlight)
4021 {
4022         int i;
4023         int numsurfaces;
4024         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4025         int numlightentities;
4026         int numlightentities_noselfshadow;
4027         int numshadowentities;
4028         int numshadowentities_noselfshadow;
4029         entity_render_t **lightentities;
4030         entity_render_t **lightentities_noselfshadow;
4031         entity_render_t **shadowentities;
4032         entity_render_t **shadowentities_noselfshadow;
4033         int *surfacelist;
4034         static unsigned char entitysides[MAX_EDICTS];
4035         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4036         vec3_t nearestpoint;
4037         vec_t distance;
4038         qboolean castshadows;
4039         int lodlinear;
4040
4041         // check if we cached this light this frame (meaning it is worth drawing)
4042         if (!rtlight->draw)
4043                 return;
4044
4045         numlightentities = rtlight->cached_numlightentities;
4046         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4047         numshadowentities = rtlight->cached_numshadowentities;
4048         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4049         numsurfaces = rtlight->cached_numsurfaces;
4050         lightentities = rtlight->cached_lightentities;
4051         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4052         shadowentities = rtlight->cached_shadowentities;
4053         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4054         shadowtrispvs = rtlight->cached_shadowtrispvs;
4055         lighttrispvs = rtlight->cached_lighttrispvs;
4056         surfacelist = rtlight->cached_surfacelist;
4057
4058         // set up a scissor rectangle for this light
4059         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4060                 return;
4061
4062         // don't let sound skip if going slow
4063         if (r_refdef.scene.extraupdate)
4064                 S_ExtraUpdate ();
4065
4066         // make this the active rtlight for rendering purposes
4067         R_Shadow_RenderMode_ActiveLight(rtlight);
4068
4069         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4070         {
4071                 // optionally draw visible shape of the shadow volumes
4072                 // for performance analysis by level designers
4073                 R_Shadow_RenderMode_VisibleShadowVolumes();
4074                 if (numsurfaces)
4075                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4076                 for (i = 0;i < numshadowentities;i++)
4077                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4078                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4079                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4080                 R_Shadow_RenderMode_VisibleLighting(false, false);
4081         }
4082
4083         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4084         {
4085                 // optionally draw the illuminated areas
4086                 // for performance analysis by level designers
4087                 R_Shadow_RenderMode_VisibleLighting(false, false);
4088                 if (numsurfaces)
4089                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4090                 for (i = 0;i < numlightentities;i++)
4091                         R_Shadow_DrawEntityLight(lightentities[i]);
4092                 for (i = 0;i < numlightentities_noselfshadow;i++)
4093                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4094         }
4095
4096         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4097
4098         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4099         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4100         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4101         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4102
4103         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4104         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4105         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4106
4107         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4108         {
4109                 float borderbias;
4110                 int side;
4111                 int size;
4112                 int castermask = 0;
4113                 int receivermask = 0;
4114                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4115                 Matrix4x4_Abs(&radiustolight);
4116
4117                 r_shadow_shadowmaplod = 0;
4118                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4119                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4120                                 r_shadow_shadowmaplod = i;
4121
4122                 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4123                         
4124                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4125
4126                 surfacesides = NULL;
4127                 if (numsurfaces)
4128                 {
4129                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4130                         {
4131                                 castermask = rtlight->static_shadowmap_casters;
4132                                 receivermask = rtlight->static_shadowmap_receivers;
4133                         }
4134                         else
4135                         {
4136                                 surfacesides = r_shadow_buffer_surfacesides;
4137                                 for(i = 0;i < numsurfaces;i++)
4138                                 {
4139                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4140                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
4141                                         castermask |= surfacesides[i];
4142                                         receivermask |= surfacesides[i];
4143                                 }
4144                         }
4145                 }
4146                 if (receivermask < 0x3F) 
4147                 {
4148                         for (i = 0;i < numlightentities;i++)
4149                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4150                         if (receivermask < 0x3F)
4151                                 for(i = 0; i < numlightentities_noselfshadow;i++)
4152                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4153                 }
4154
4155                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4156
4157                 if (receivermask)
4158                 {
4159                         for (i = 0;i < numshadowentities;i++)
4160                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4161                         for (i = 0;i < numshadowentities_noselfshadow;i++)
4162                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
4163                 }
4164
4165                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4166
4167                 // render shadow casters into 6 sided depth texture
4168                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4169                 {
4170                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4171                         if (! (castermask & (1 << side))) continue;
4172                         if (numsurfaces)
4173                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4174                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4175                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4176                 }
4177
4178                 if (numlightentities_noselfshadow)
4179                 {
4180                         // render lighting using the depth texture as shadowmap
4181                         // draw lighting in the unmasked areas
4182                         R_Shadow_RenderMode_Lighting(false, false, true);
4183                         for (i = 0;i < numlightentities_noselfshadow;i++)
4184                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4185                 }
4186
4187                 // render shadow casters into 6 sided depth texture
4188                 if (numshadowentities_noselfshadow)
4189                 {
4190                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4191                         {
4192                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4193                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4194                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4195                         }
4196                 }
4197
4198                 // render lighting using the depth texture as shadowmap
4199                 // draw lighting in the unmasked areas
4200                 R_Shadow_RenderMode_Lighting(false, false, true);
4201                 // draw lighting in the unmasked areas
4202                 if (numsurfaces)
4203                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4204                 for (i = 0;i < numlightentities;i++)
4205                         R_Shadow_DrawEntityLight(lightentities[i]);
4206         }
4207         else if (castshadows && vid.stencil)
4208         {
4209                 // draw stencil shadow volumes to mask off pixels that are in shadow
4210                 // so that they won't receive lighting
4211                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4212                 R_Shadow_ClearStencil();
4213
4214                 if (numsurfaces)
4215                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4216                 for (i = 0;i < numshadowentities;i++)
4217                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4218
4219                 // draw lighting in the unmasked areas
4220                 R_Shadow_RenderMode_Lighting(true, false, false);
4221                 for (i = 0;i < numlightentities_noselfshadow;i++)
4222                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4223
4224                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4225                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4226
4227                 // draw lighting in the unmasked areas
4228                 R_Shadow_RenderMode_Lighting(true, false, false);
4229                 if (numsurfaces)
4230                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4231                 for (i = 0;i < numlightentities;i++)
4232                         R_Shadow_DrawEntityLight(lightentities[i]);
4233         }
4234         else
4235         {
4236                 // draw lighting in the unmasked areas
4237                 R_Shadow_RenderMode_Lighting(false, false, false);
4238                 if (numsurfaces)
4239                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4240                 for (i = 0;i < numlightentities;i++)
4241                         R_Shadow_DrawEntityLight(lightentities[i]);
4242                 for (i = 0;i < numlightentities_noselfshadow;i++)
4243                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4244         }
4245
4246         if (r_shadow_usingdeferredprepass)
4247         {
4248                 // when rendering deferred lighting, we simply rasterize the box
4249                 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4250                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
4251                 else if (castshadows && vid.stencil)
4252                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
4253                 else
4254                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
4255         }
4256
4257         if (r_shadow_particletrace.integer)
4258                 R_Shadow_RenderParticlesForLight(rtlight);
4259 }
4260
4261 static void R_Shadow_FreeDeferred(void)
4262 {
4263         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4264         r_shadow_prepassgeometryfbo = 0;
4265
4266         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4267         r_shadow_prepasslightingdiffusespecularfbo = 0;
4268
4269         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4270         r_shadow_prepasslightingdiffusefbo = 0;
4271
4272         if (r_shadow_prepassgeometrydepthtexture)
4273                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4274         r_shadow_prepassgeometrydepthtexture = NULL;
4275
4276         if (r_shadow_prepassgeometrydepthcolortexture)
4277                 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4278         r_shadow_prepassgeometrydepthcolortexture = NULL;
4279
4280         if (r_shadow_prepassgeometrynormalmaptexture)
4281                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4282         r_shadow_prepassgeometrynormalmaptexture = NULL;
4283
4284         if (r_shadow_prepasslightingdiffusetexture)
4285                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4286         r_shadow_prepasslightingdiffusetexture = NULL;
4287
4288         if (r_shadow_prepasslightingspeculartexture)
4289                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4290         r_shadow_prepasslightingspeculartexture = NULL;
4291 }
4292
4293 void R_Shadow_DrawPrepass(void)
4294 {
4295         int i;
4296         int flag;
4297         int lnum;
4298         size_t lightindex;
4299         dlight_t *light;
4300         size_t range;
4301         entity_render_t *ent;
4302         float clearcolor[4];
4303
4304         R_Mesh_ResetTextureState();
4305         GL_DepthMask(true);
4306         GL_ColorMask(1,1,1,1);
4307         GL_BlendFunc(GL_ONE, GL_ZERO);
4308         GL_Color(1,1,1,1);
4309         GL_DepthTest(true);
4310         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4311         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4312         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4313         if (r_timereport_active)
4314                 R_TimeReport("prepasscleargeom");
4315
4316         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4317                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4318         if (r_timereport_active)
4319                 R_TimeReport("prepassworld");
4320
4321         for (i = 0;i < r_refdef.scene.numentities;i++)
4322         {
4323                 if (!r_refdef.viewcache.entityvisible[i])
4324                         continue;
4325                 ent = r_refdef.scene.entities[i];
4326                 if (ent->model && ent->model->DrawPrepass != NULL)
4327                         ent->model->DrawPrepass(ent);
4328         }
4329
4330         if (r_timereport_active)
4331                 R_TimeReport("prepassmodels");
4332
4333         GL_DepthMask(false);
4334         GL_ColorMask(1,1,1,1);
4335         GL_Color(1,1,1,1);
4336         GL_DepthTest(true);
4337         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4338         Vector4Set(clearcolor, 0, 0, 0, 0);
4339         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4340         if (r_timereport_active)
4341                 R_TimeReport("prepassclearlit");
4342
4343         R_Shadow_RenderMode_Begin();
4344
4345         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4346         if (r_shadow_debuglight.integer >= 0)
4347         {
4348                 lightindex = r_shadow_debuglight.integer;
4349                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4350                 if (light && (light->flags & flag) && light->rtlight.draw)
4351                         R_Shadow_DrawLight(&light->rtlight);
4352         }
4353         else
4354         {
4355                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4356                 for (lightindex = 0;lightindex < range;lightindex++)
4357                 {
4358                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4359                         if (light && (light->flags & flag) && light->rtlight.draw)
4360                                 R_Shadow_DrawLight(&light->rtlight);
4361                 }
4362         }
4363         if (r_refdef.scene.rtdlight)
4364                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4365                         if (r_refdef.scene.lights[lnum]->draw)
4366                                 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4367
4368         R_Mesh_ResetRenderTargets();
4369
4370         R_Shadow_RenderMode_End();
4371
4372         if (r_timereport_active)
4373                 R_TimeReport("prepasslights");
4374 }
4375
4376 void R_Shadow_DrawLightSprites(void);
4377 void R_Shadow_PrepareLights(void)
4378 {
4379         int flag;
4380         int lnum;
4381         size_t lightindex;
4382         dlight_t *light;
4383         size_t range;
4384         float f;
4385         GLenum status;
4386
4387         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4388                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4389                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
4390                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4391                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4392                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4393                 R_Shadow_FreeShadowMaps();
4394
4395         r_shadow_usingshadowmaportho = false;
4396
4397         switch (vid.renderpath)
4398         {
4399         case RENDERPATH_GL20:
4400         case RENDERPATH_D3D9:
4401         case RENDERPATH_D3D10:
4402         case RENDERPATH_D3D11:
4403         case RENDERPATH_SOFT:
4404         case RENDERPATH_GLES2:
4405                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4406                 {
4407                         r_shadow_usingdeferredprepass = false;
4408                         if (r_shadow_prepass_width)
4409                                 R_Shadow_FreeDeferred();
4410                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4411                         break;
4412                 }
4413
4414                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4415                 {
4416                         R_Shadow_FreeDeferred();
4417
4418                         r_shadow_usingdeferredprepass = true;
4419                         r_shadow_prepass_width = vid.width;
4420                         r_shadow_prepass_height = vid.height;
4421                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4422                         switch (vid.renderpath)
4423                         {
4424                         case RENDERPATH_D3D9:
4425                                 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4426                                 break;
4427                         default:
4428                                 break;
4429                         }
4430                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4431                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4432                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4433
4434                         // set up the geometry pass fbo (depth + normalmap)
4435                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4436                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4437                         // render depth into one texture and normalmap into the other
4438                         if (qglDrawBuffersARB)
4439                         {
4440                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4441                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4442                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4443                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4444                                 {
4445                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4446                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4447                                         r_shadow_usingdeferredprepass = false;
4448                                 }
4449                         }
4450
4451                         // set up the lighting pass fbo (diffuse + specular)
4452                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4453                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4454                         // render diffuse into one texture and specular into another,
4455                         // with depth and normalmap bound as textures,
4456                         // with depth bound as attachment as well
4457                         if (qglDrawBuffersARB)
4458                         {
4459                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4460                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4461                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4462                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4463                                 {
4464                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4465                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4466                                         r_shadow_usingdeferredprepass = false;
4467                                 }
4468                         }
4469
4470                         // set up the lighting pass fbo (diffuse)
4471                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4472                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4473                         // render diffuse into one texture,
4474                         // with depth and normalmap bound as textures,
4475                         // with depth bound as attachment as well
4476                         if (qglDrawBuffersARB)
4477                         {
4478                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4479                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4480                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4481                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4482                                 {
4483                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4484                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4485                                         r_shadow_usingdeferredprepass = false;
4486                                 }
4487                         }
4488                 }
4489                 break;
4490         case RENDERPATH_GL13:
4491         case RENDERPATH_GL11:
4492                 r_shadow_usingdeferredprepass = false;
4493                 break;
4494         }
4495
4496         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);
4497
4498         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4499         if (r_shadow_debuglight.integer >= 0)
4500         {
4501                 lightindex = r_shadow_debuglight.integer;
4502                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4503                 if (light && (light->flags & flag))
4504                         R_Shadow_PrepareLight(&light->rtlight);
4505         }
4506         else
4507         {
4508                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4509                 for (lightindex = 0;lightindex < range;lightindex++)
4510                 {
4511                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4512                         if (light && (light->flags & flag))
4513                                 R_Shadow_PrepareLight(&light->rtlight);
4514                 }
4515         }
4516         if (r_refdef.scene.rtdlight)
4517         {
4518                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4519                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4520         }
4521         else if(gl_flashblend.integer)
4522         {
4523                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4524                 {
4525                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4526                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4527                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4528                 }
4529         }
4530
4531         if (r_editlights.integer)
4532                 R_Shadow_DrawLightSprites();
4533
4534         R_Shadow_UpdateBounceGridTexture();
4535 }
4536
4537 void R_Shadow_DrawLights(void)
4538 {
4539         int flag;
4540         int lnum;
4541         size_t lightindex;
4542         dlight_t *light;
4543         size_t range;
4544
4545         R_Shadow_RenderMode_Begin();
4546
4547         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4548         if (r_shadow_debuglight.integer >= 0)
4549         {
4550                 lightindex = r_shadow_debuglight.integer;
4551                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4552                 if (light && (light->flags & flag))
4553                         R_Shadow_DrawLight(&light->rtlight);
4554         }
4555         else
4556         {
4557                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4558                 for (lightindex = 0;lightindex < range;lightindex++)
4559                 {
4560                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4561                         if (light && (light->flags & flag))
4562                                 R_Shadow_DrawLight(&light->rtlight);
4563                 }
4564         }
4565         if (r_refdef.scene.rtdlight)
4566                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4567                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4568
4569         R_Shadow_RenderMode_End();
4570 }
4571
4572 extern const float r_screenvertex3f[12];
4573 extern void R_SetupView(qboolean allowwaterclippingplane);
4574 extern void R_ResetViewRendering3D(void);
4575 extern void R_ResetViewRendering2D(void);
4576 extern cvar_t r_shadows;
4577 extern cvar_t r_shadows_darken;
4578 extern cvar_t r_shadows_drawafterrtlighting;
4579 extern cvar_t r_shadows_castfrombmodels;
4580 extern cvar_t r_shadows_throwdistance;
4581 extern cvar_t r_shadows_throwdirection;
4582 extern cvar_t r_shadows_focus;
4583 extern cvar_t r_shadows_shadowmapscale;
4584
4585 void R_Shadow_PrepareModelShadows(void)
4586 {
4587         int i;
4588         float scale, size, radius, dot1, dot2;
4589         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4590         entity_render_t *ent;
4591
4592         if (!r_refdef.scene.numentities)
4593                 return;
4594
4595         switch (r_shadow_shadowmode)
4596         {
4597         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4598                 if (r_shadows.integer >= 2) 
4599                         break;
4600                 // fall through
4601         case R_SHADOW_SHADOWMODE_STENCIL:
4602                 for (i = 0;i < r_refdef.scene.numentities;i++)
4603                 {
4604                         ent = r_refdef.scene.entities[i];
4605                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4606                                 R_AnimCache_GetEntity(ent, false, false);
4607                 }
4608                 return;
4609         default:
4610                 return;
4611         }
4612
4613         size = 2*r_shadow_shadowmapmaxsize;
4614         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4615         radius = 0.5f * size / scale;
4616
4617         Math_atov(r_shadows_throwdirection.string, shadowdir);
4618         VectorNormalize(shadowdir);
4619         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4620         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4621         if (fabs(dot1) <= fabs(dot2))
4622                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4623         else
4624                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4625         VectorNormalize(shadowforward);
4626         CrossProduct(shadowdir, shadowforward, shadowright);
4627         Math_atov(r_shadows_focus.string, shadowfocus);
4628         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4629         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4630         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4631         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4632         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4633                 dot1 = 1;
4634         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4635
4636         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4637         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4638         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4639         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4640         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4641         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4642
4643         for (i = 0;i < r_refdef.scene.numentities;i++)
4644         {
4645                 ent = r_refdef.scene.entities[i];
4646                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4647                         continue;
4648                 // cast shadows from anything of the map (submodels are optional)
4649                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4650                         R_AnimCache_GetEntity(ent, false, false);
4651         }
4652 }
4653
4654 void R_DrawModelShadowMaps(void)
4655 {
4656         int i;
4657         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4658         entity_render_t *ent;
4659         vec3_t relativelightorigin;
4660         vec3_t relativelightdirection, relativeforward, relativeright;
4661         vec3_t relativeshadowmins, relativeshadowmaxs;
4662         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4663         float m[12];
4664         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4665         r_viewport_t viewport;
4666         GLuint fbo = 0;
4667         float clearcolor[4];
4668
4669         if (!r_refdef.scene.numentities)
4670                 return;
4671
4672         switch (r_shadow_shadowmode)
4673         {
4674         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4675                 break;
4676         default:
4677                 return;
4678         }
4679
4680         R_ResetViewRendering3D();
4681         R_Shadow_RenderMode_Begin();
4682         R_Shadow_RenderMode_ActiveLight(NULL);
4683
4684         switch (r_shadow_shadowmode)
4685         {
4686         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4687                 if (!r_shadow_shadowmap2dtexture)
4688                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4689                 fbo = r_shadow_fbo2d;
4690                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4691                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4692                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4693                 break;
4694         default:
4695                 break;
4696         }
4697
4698         size = 2*r_shadow_shadowmapmaxsize;
4699         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4700         radius = 0.5f / scale;
4701         nearclip = -r_shadows_throwdistance.value;
4702         farclip = r_shadows_throwdistance.value;
4703         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4704
4705         r_shadow_shadowmap_parameters[0] = size;
4706         r_shadow_shadowmap_parameters[1] = size;
4707         r_shadow_shadowmap_parameters[2] = 1.0;
4708         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4709
4710         Math_atov(r_shadows_throwdirection.string, shadowdir);
4711         VectorNormalize(shadowdir);
4712         Math_atov(r_shadows_focus.string, shadowfocus);
4713         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4714         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4715         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4716         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4717         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4718         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4719         if (fabs(dot1) <= fabs(dot2)) 
4720                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4721         else
4722                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4723         VectorNormalize(shadowforward);
4724         VectorM(scale, shadowforward, &m[0]);
4725         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4726                 dot1 = 1;
4727         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4728         CrossProduct(shadowdir, shadowforward, shadowright);
4729         VectorM(scale, shadowright, &m[4]);
4730         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4731         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4732         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4733         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4734         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4735         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4736
4737         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4738
4739         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4740         R_SetupShader_DepthOrShadow();
4741         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4742         GL_DepthMask(true);
4743         GL_DepthTest(true);
4744         R_SetViewport(&viewport);
4745         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4746         Vector4Set(clearcolor, 1,1,1,1);
4747         // in D3D9 we have to render to a color texture shadowmap
4748         // in GL we render directly to a depth texture only
4749         if (r_shadow_shadowmap2dtexture)
4750                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4751         else
4752                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4753         // render into a slightly restricted region so that the borders of the
4754         // shadowmap area fade away, rather than streaking across everything
4755         // outside the usable area
4756         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4757
4758 #if 0
4759         // debugging
4760         R_Mesh_ResetRenderTargets();
4761         R_SetupShader_ShowDepth();
4762         GL_ColorMask(1,1,1,1);
4763         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4764 #endif
4765
4766         for (i = 0;i < r_refdef.scene.numentities;i++)
4767         {
4768                 ent = r_refdef.scene.entities[i];
4769
4770                 // cast shadows from anything of the map (submodels are optional)
4771                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4772                 {
4773                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4774                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4775                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4776                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4777                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4778                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4779                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4780                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4781                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4782                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4783                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4784                         RSurf_ActiveModelEntity(ent, false, false, false);
4785                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4786                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4787                 }
4788         }
4789
4790 #if 0
4791         if (r_test.integer)
4792         {
4793                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4794                 CHECKGLERROR
4795                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4796                 CHECKGLERROR
4797                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4798                 Cvar_SetValueQuick(&r_test, 0);
4799                 Z_Free(rawpixels);
4800         }
4801 #endif
4802
4803         R_Shadow_RenderMode_End();
4804
4805         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4806         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4807         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4808         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4809         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4810         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4811
4812         switch (vid.renderpath)
4813         {
4814         case RENDERPATH_GL11:
4815         case RENDERPATH_GL13:
4816         case RENDERPATH_GL20:
4817         case RENDERPATH_SOFT:
4818         case RENDERPATH_GLES2:
4819                 break;
4820         case RENDERPATH_D3D9:
4821         case RENDERPATH_D3D10:
4822         case RENDERPATH_D3D11:
4823 #ifdef OPENGL_ORIENTATION
4824                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4825                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
4826                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
4827                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
4828 #else
4829                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4830                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
4831                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
4832                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
4833 #endif
4834                 break;
4835         }
4836
4837         r_shadow_usingshadowmaportho = true;
4838         switch (r_shadow_shadowmode)
4839         {
4840         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4841                 r_shadow_usingshadowmap2d = true;
4842                 break;
4843         default:
4844                 break;
4845         }
4846 }
4847
4848 void R_DrawModelShadows(void)
4849 {
4850         int i;
4851         float relativethrowdistance;
4852         entity_render_t *ent;
4853         vec3_t relativelightorigin;
4854         vec3_t relativelightdirection;
4855         vec3_t relativeshadowmins, relativeshadowmaxs;
4856         vec3_t tmp, shadowdir;
4857
4858         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4859                 return;
4860
4861         R_ResetViewRendering3D();
4862         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4863         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4864         R_Shadow_RenderMode_Begin();
4865         R_Shadow_RenderMode_ActiveLight(NULL);
4866         r_shadow_lightscissor[0] = r_refdef.view.x;
4867         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4868         r_shadow_lightscissor[2] = r_refdef.view.width;
4869         r_shadow_lightscissor[3] = r_refdef.view.height;
4870         R_Shadow_RenderMode_StencilShadowVolumes(false);
4871
4872         // get shadow dir
4873         if (r_shadows.integer == 2)
4874         {
4875                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4876                 VectorNormalize(shadowdir);
4877         }
4878
4879         R_Shadow_ClearStencil();
4880
4881         for (i = 0;i < r_refdef.scene.numentities;i++)
4882         {
4883                 ent = r_refdef.scene.entities[i];
4884
4885                 // cast shadows from anything of the map (submodels are optional)
4886                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4887                 {
4888                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4889                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4890                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4891                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4892                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4893                         else
4894                         {
4895                                 if(ent->entitynumber != 0)
4896                                 {
4897                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4898                                         {
4899                                                 // FIXME handle this
4900                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4901                                         }
4902                                         else
4903                                         {
4904                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4905                                                 int entnum, entnum2, recursion;
4906                                                 entnum = entnum2 = ent->entitynumber;
4907                                                 for(recursion = 32; recursion > 0; --recursion)
4908                                                 {
4909                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
4910                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4911                                                                 entnum = entnum2;
4912                                                         else
4913                                                                 break;
4914                                                 }
4915                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4916                                                 {
4917                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4918                                                         // transform into modelspace of OUR entity
4919                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4920                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4921                                                 }
4922                                                 else
4923                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4924                                         }
4925                                 }
4926                                 else
4927                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
4928                         }
4929
4930                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4931                         RSurf_ActiveModelEntity(ent, false, false, false);
4932                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4933                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4934                 }
4935         }
4936
4937         // not really the right mode, but this will disable any silly stencil features
4938         R_Shadow_RenderMode_End();
4939
4940         // set up ortho view for rendering this pass
4941         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4942         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4943         //GL_ScissorTest(true);
4944         //R_EntityMatrix(&identitymatrix);
4945         //R_Mesh_ResetTextureState();
4946         R_ResetViewRendering2D();
4947
4948         // set up a darkening blend on shadowed areas
4949         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4950         //GL_DepthRange(0, 1);
4951         //GL_DepthTest(false);
4952         //GL_DepthMask(false);
4953         //GL_PolygonOffset(0, 0);CHECKGLERROR
4954         GL_Color(0, 0, 0, r_shadows_darken.value);
4955         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4956         //GL_DepthFunc(GL_ALWAYS);
4957         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4958
4959         // apply the blend to the shadowed areas
4960         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4961         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4962         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4963
4964         // restore the viewport
4965         R_SetViewport(&r_refdef.view.viewport);
4966
4967         // restore other state to normal
4968         //R_Shadow_RenderMode_End();
4969 }
4970
4971 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4972 {
4973         float zdist;
4974         vec3_t centerorigin;
4975         float vertex3f[12];
4976         // if it's too close, skip it
4977         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4978                 return;
4979         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4980         if (zdist < 32)
4981                 return;
4982         if (usequery && r_numqueries + 2 <= r_maxqueries)
4983         {
4984                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4985                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4986                 // 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
4987                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4988
4989                 switch(vid.renderpath)
4990                 {
4991                 case RENDERPATH_GL20:
4992                 case RENDERPATH_GL13:
4993                 case RENDERPATH_GL11:
4994                 case RENDERPATH_GLES2:
4995                         CHECKGLERROR
4996                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4997                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4998                         GL_DepthFunc(GL_ALWAYS);
4999                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5000                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5001                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5002                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5003                         GL_DepthFunc(GL_LEQUAL);
5004                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5005                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5006                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5007                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5008                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5009                         CHECKGLERROR
5010                         break;
5011                 case RENDERPATH_D3D9:
5012                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5013                         break;
5014                 case RENDERPATH_D3D10:
5015                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5016                         break;
5017                 case RENDERPATH_D3D11:
5018                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5019                         break;
5020                 case RENDERPATH_SOFT:
5021                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5022                         break;
5023                 }
5024         }
5025         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5026 }
5027
5028 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5029
5030 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5031 {
5032         vec3_t color;
5033         GLint allpixels = 0, visiblepixels = 0;
5034         // now we have to check the query result
5035         if (rtlight->corona_queryindex_visiblepixels)
5036         {
5037                 switch(vid.renderpath)
5038                 {
5039                 case RENDERPATH_GL20:
5040                 case RENDERPATH_GL13:
5041                 case RENDERPATH_GL11:
5042                 case RENDERPATH_GLES2:
5043                         CHECKGLERROR
5044                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5045                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5046                         CHECKGLERROR
5047                         break;
5048                 case RENDERPATH_D3D9:
5049                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5050                         break;
5051                 case RENDERPATH_D3D10:
5052                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5053                         break;
5054                 case RENDERPATH_D3D11:
5055                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5056                         break;
5057                 case RENDERPATH_SOFT:
5058                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5059                         break;
5060                 }
5061                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5062                 if (visiblepixels < 1 || allpixels < 1)
5063                         return;
5064                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5065                 cscale *= rtlight->corona_visibility;
5066         }
5067         else
5068         {
5069                 // FIXME: these traces should scan all render entities instead of cl.world
5070                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
5071                         return;
5072         }
5073         VectorScale(rtlight->currentcolor, cscale, color);
5074         if (VectorLength(color) > (1.0f / 256.0f))
5075         {
5076                 float vertex3f[12];
5077                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5078                 if(negated)
5079                 {
5080                         VectorNegate(color, color);
5081                         switch(vid.renderpath)
5082                         {
5083                         case RENDERPATH_GL11:
5084                         case RENDERPATH_GL13:
5085                         case RENDERPATH_GL20:
5086                         case RENDERPATH_GLES2:
5087                                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5088                                 break;
5089                         case RENDERPATH_D3D9:
5090 #ifdef SUPPORTD3D
5091                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5092 #endif
5093                                 break;
5094                         case RENDERPATH_D3D10:
5095                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5096                                 break;
5097                         case RENDERPATH_D3D11:
5098                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5099                                 break;
5100                         case RENDERPATH_SOFT:
5101                                 DPSOFTRAST_BlendSubtract(true);
5102                                 break;
5103                         }
5104                 }
5105                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5106                 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);
5107                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5108                 if(negated)
5109                 {
5110                         switch(vid.renderpath)
5111                         {
5112                         case RENDERPATH_GL11:
5113                         case RENDERPATH_GL13:
5114                         case RENDERPATH_GL20:
5115                         case RENDERPATH_GLES2:
5116                                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5117                                 break;
5118                         case RENDERPATH_D3D9:
5119 #ifdef SUPPORTD3D
5120                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5121 #endif
5122                                 break;
5123                         case RENDERPATH_D3D10:
5124                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5125                                 break;
5126                         case RENDERPATH_D3D11:
5127                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5128                                 break;
5129                         case RENDERPATH_SOFT:
5130                                 DPSOFTRAST_BlendSubtract(false);
5131                                 break;
5132                         }
5133                 }
5134         }
5135 }
5136
5137 void R_Shadow_DrawCoronas(void)
5138 {
5139         int i, flag;
5140         qboolean usequery = false;
5141         size_t lightindex;
5142         dlight_t *light;
5143         rtlight_t *rtlight;
5144         size_t range;
5145         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5146                 return;
5147         if (r_waterstate.renderingscene)
5148                 return;
5149         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5150         R_EntityMatrix(&identitymatrix);
5151
5152         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5153
5154         // check occlusion of coronas
5155         // use GL_ARB_occlusion_query if available
5156         // otherwise use raytraces
5157         r_numqueries = 0;
5158         switch (vid.renderpath)
5159         {
5160         case RENDERPATH_GL11:
5161         case RENDERPATH_GL13:
5162         case RENDERPATH_GL20:
5163         case RENDERPATH_GLES2:
5164                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5165                 if (usequery)
5166                 {
5167                         GL_ColorMask(0,0,0,0);
5168                         if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5169                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5170                         {
5171                                 i = r_maxqueries;
5172                                 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5173                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5174                                 CHECKGLERROR
5175                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5176                                 CHECKGLERROR
5177                         }
5178                         RSurf_ActiveWorldEntity();
5179                         GL_BlendFunc(GL_ONE, GL_ZERO);
5180                         GL_CullFace(GL_NONE);
5181                         GL_DepthMask(false);
5182                         GL_DepthRange(0, 1);
5183                         GL_PolygonOffset(0, 0);
5184                         GL_DepthTest(true);
5185                         R_Mesh_ResetTextureState();
5186                         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5187                 }
5188                 break;
5189         case RENDERPATH_D3D9:
5190                 usequery = false;
5191                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5192                 break;
5193         case RENDERPATH_D3D10:
5194                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5195                 break;
5196         case RENDERPATH_D3D11:
5197                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5198                 break;
5199         case RENDERPATH_SOFT:
5200                 usequery = false;
5201                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5202                 break;
5203         }
5204         for (lightindex = 0;lightindex < range;lightindex++)
5205         {
5206                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5207                 if (!light)
5208                         continue;
5209                 rtlight = &light->rtlight;
5210                 rtlight->corona_visibility = 0;
5211                 rtlight->corona_queryindex_visiblepixels = 0;
5212                 rtlight->corona_queryindex_allpixels = 0;
5213                 if (!(rtlight->flags & flag))
5214                         continue;
5215                 if (rtlight->corona <= 0)
5216                         continue;
5217                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5218                         continue;
5219                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5220         }
5221         for (i = 0;i < r_refdef.scene.numlights;i++)
5222         {
5223                 rtlight = r_refdef.scene.lights[i];
5224                 rtlight->corona_visibility = 0;
5225                 rtlight->corona_queryindex_visiblepixels = 0;
5226                 rtlight->corona_queryindex_allpixels = 0;
5227                 if (!(rtlight->flags & flag))
5228                         continue;
5229                 if (rtlight->corona <= 0)
5230                         continue;
5231                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5232         }
5233         if (usequery)
5234                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5235
5236         // now draw the coronas using the query data for intensity info
5237         for (lightindex = 0;lightindex < range;lightindex++)
5238         {
5239                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5240                 if (!light)
5241                         continue;
5242                 rtlight = &light->rtlight;
5243                 if (rtlight->corona_visibility <= 0)
5244                         continue;
5245                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5246         }
5247         for (i = 0;i < r_refdef.scene.numlights;i++)
5248         {
5249                 rtlight = r_refdef.scene.lights[i];
5250                 if (rtlight->corona_visibility <= 0)
5251                         continue;
5252                 if (gl_flashblend.integer)
5253                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5254                 else
5255                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5256         }
5257 }
5258
5259
5260
5261 dlight_t *R_Shadow_NewWorldLight(void)
5262 {
5263         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5264 }
5265
5266 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)
5267 {
5268         matrix4x4_t matrix;
5269         // validate parameters
5270         if (style < 0 || style >= MAX_LIGHTSTYLES)
5271         {
5272                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5273                 style = 0;
5274         }
5275         if (!cubemapname)
5276                 cubemapname = "";
5277
5278         // copy to light properties
5279         VectorCopy(origin, light->origin);
5280         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5281         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5282         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5283         /*
5284         light->color[0] = max(color[0], 0);
5285         light->color[1] = max(color[1], 0);
5286         light->color[2] = max(color[2], 0);
5287         */
5288         light->color[0] = color[0];
5289         light->color[1] = color[1];
5290         light->color[2] = color[2];
5291         light->radius = max(radius, 0);
5292         light->style = style;
5293         light->shadow = shadowenable;
5294         light->corona = corona;
5295         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5296         light->coronasizescale = coronasizescale;
5297         light->ambientscale = ambientscale;
5298         light->diffusescale = diffusescale;
5299         light->specularscale = specularscale;
5300         light->flags = flags;
5301
5302         // update renderable light data
5303         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5304         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);
5305 }
5306
5307 void R_Shadow_FreeWorldLight(dlight_t *light)
5308 {
5309         if (r_shadow_selectedlight == light)
5310                 r_shadow_selectedlight = NULL;
5311         R_RTLight_Uncompile(&light->rtlight);
5312         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5313 }
5314
5315 void R_Shadow_ClearWorldLights(void)
5316 {
5317         size_t lightindex;
5318         dlight_t *light;
5319         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5320         for (lightindex = 0;lightindex < range;lightindex++)
5321         {
5322                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5323                 if (light)
5324                         R_Shadow_FreeWorldLight(light);
5325         }
5326         r_shadow_selectedlight = NULL;
5327 }
5328
5329 void R_Shadow_SelectLight(dlight_t *light)
5330 {
5331         if (r_shadow_selectedlight)
5332                 r_shadow_selectedlight->selected = false;
5333         r_shadow_selectedlight = light;
5334         if (r_shadow_selectedlight)
5335                 r_shadow_selectedlight->selected = true;
5336 }
5337
5338 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5339 {
5340         // this is never batched (there can be only one)
5341         float vertex3f[12];
5342         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5343         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5344         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5345 }
5346
5347 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5348 {
5349         float intensity;
5350         float s;
5351         vec3_t spritecolor;
5352         skinframe_t *skinframe;
5353         float vertex3f[12];
5354
5355         // this is never batched (due to the ent parameter changing every time)
5356         // so numsurfaces == 1 and surfacelist[0] == lightnumber
5357         const dlight_t *light = (dlight_t *)ent;
5358         s = EDLIGHTSPRSIZE;
5359
5360         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5361
5362         intensity = 0.5f;
5363         VectorScale(light->color, intensity, spritecolor);
5364         if (VectorLength(spritecolor) < 0.1732f)
5365                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5366         if (VectorLength(spritecolor) > 1.0f)
5367                 VectorNormalize(spritecolor);
5368
5369         // draw light sprite
5370         if (light->cubemapname[0] && !light->shadow)
5371                 skinframe = r_editlights_sprcubemapnoshadowlight;
5372         else if (light->cubemapname[0])
5373                 skinframe = r_editlights_sprcubemaplight;
5374         else if (!light->shadow)
5375                 skinframe = r_editlights_sprnoshadowlight;
5376         else
5377                 skinframe = r_editlights_sprlight;
5378
5379         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);
5380         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5381
5382         // draw selection sprite if light is selected
5383         if (light->selected)
5384         {
5385                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5386                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5387                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5388         }
5389 }
5390
5391 void R_Shadow_DrawLightSprites(void)
5392 {
5393         size_t lightindex;
5394         dlight_t *light;
5395         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5396         for (lightindex = 0;lightindex < range;lightindex++)
5397         {
5398                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5399                 if (light)
5400                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5401         }
5402         if (!r_editlights_lockcursor)
5403                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5404 }
5405
5406 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5407 {
5408         unsigned int range;
5409         dlight_t *light;
5410         rtlight_t *rtlight;
5411         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5412         if (lightindex >= range)
5413                 return -1;
5414         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5415         if (!light)
5416                 return 0;
5417         rtlight = &light->rtlight;
5418         //if (!(rtlight->flags & flag))
5419         //      return 0;
5420         VectorCopy(rtlight->shadoworigin, origin);
5421         *radius = rtlight->radius;
5422         VectorCopy(rtlight->color, color);
5423         return 1;
5424 }
5425
5426 void R_Shadow_SelectLightInView(void)
5427 {
5428         float bestrating, rating, temp[3];
5429         dlight_t *best;
5430         size_t lightindex;
5431         dlight_t *light;
5432         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5433         best = NULL;
5434         bestrating = 0;
5435
5436         if (r_editlights_lockcursor)
5437                 return;
5438         for (lightindex = 0;lightindex < range;lightindex++)
5439         {
5440                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5441                 if (!light)
5442                         continue;
5443                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5444                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5445                 if (rating >= 0.95)
5446                 {
5447                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5448                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5449                         {
5450                                 bestrating = rating;
5451                                 best = light;
5452                         }
5453                 }
5454         }
5455         R_Shadow_SelectLight(best);
5456 }
5457
5458 void R_Shadow_LoadWorldLights(void)
5459 {
5460         int n, a, style, shadow, flags;
5461         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5462         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5463         if (cl.worldmodel == NULL)
5464         {
5465                 Con_Print("No map loaded.\n");
5466                 return;
5467         }
5468         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5469         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5470         if (lightsstring)
5471         {
5472                 s = lightsstring;
5473                 n = 0;
5474                 while (*s)
5475                 {
5476                         t = s;
5477                         /*
5478                         shadow = true;
5479                         for (;COM_Parse(t, true) && strcmp(
5480                         if (COM_Parse(t, true))
5481                         {
5482                                 if (com_token[0] == '!')
5483                                 {
5484                                         shadow = false;
5485                                         origin[0] = atof(com_token+1);
5486                                 }
5487                                 else
5488                                         origin[0] = atof(com_token);
5489                                 if (Com_Parse(t
5490                         }
5491                         */
5492                         t = s;
5493                         while (*s && *s != '\n' && *s != '\r')
5494                                 s++;
5495                         if (!*s)
5496                                 break;
5497                         tempchar = *s;
5498                         shadow = true;
5499                         // check for modifier flags
5500                         if (*t == '!')
5501                         {
5502                                 shadow = false;
5503                                 t++;
5504                         }
5505                         *s = 0;
5506 #if _MSC_VER >= 1400
5507 #define sscanf sscanf_s
5508 #endif
5509                         cubemapname[sizeof(cubemapname)-1] = 0;
5510 #if MAX_QPATH != 128
5511 #error update this code if MAX_QPATH changes
5512 #endif
5513                         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
5514 #if _MSC_VER >= 1400
5515 , sizeof(cubemapname)
5516 #endif
5517 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5518                         *s = tempchar;
5519                         if (a < 18)
5520                                 flags = LIGHTFLAG_REALTIMEMODE;
5521                         if (a < 17)
5522                                 specularscale = 1;
5523                         if (a < 16)
5524                                 diffusescale = 1;
5525                         if (a < 15)
5526                                 ambientscale = 0;
5527                         if (a < 14)
5528                                 coronasizescale = 0.25f;
5529                         if (a < 13)
5530                                 VectorClear(angles);
5531                         if (a < 10)
5532                                 corona = 0;
5533                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5534                                 cubemapname[0] = 0;
5535                         // remove quotes on cubemapname
5536                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5537                         {
5538                                 size_t namelen;
5539                                 namelen = strlen(cubemapname) - 2;
5540                                 memmove(cubemapname, cubemapname + 1, namelen);
5541                                 cubemapname[namelen] = '\0';
5542                         }
5543                         if (a < 8)
5544                         {
5545                                 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);
5546                                 break;
5547                         }
5548                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5549                         if (*s == '\r')
5550                                 s++;
5551                         if (*s == '\n')
5552                                 s++;
5553                         n++;
5554                 }
5555                 if (*s)
5556                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5557                 Mem_Free(lightsstring);
5558         }
5559 }
5560
5561 void R_Shadow_SaveWorldLights(void)
5562 {
5563         size_t lightindex;
5564         dlight_t *light;
5565         size_t bufchars, bufmaxchars;
5566         char *buf, *oldbuf;
5567         char name[MAX_QPATH];
5568         char line[MAX_INPUTLINE];
5569         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5570         // I hate lines which are 3 times my screen size :( --blub
5571         if (!range)
5572                 return;
5573         if (cl.worldmodel == NULL)
5574         {
5575                 Con_Print("No map loaded.\n");
5576                 return;
5577         }
5578         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5579         bufchars = bufmaxchars = 0;
5580         buf = NULL;
5581         for (lightindex = 0;lightindex < range;lightindex++)
5582         {
5583                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5584                 if (!light)
5585                         continue;
5586                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5587                         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);
5588                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5589                         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]);
5590                 else
5591                         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);
5592                 if (bufchars + strlen(line) > bufmaxchars)
5593                 {
5594                         bufmaxchars = bufchars + strlen(line) + 2048;
5595                         oldbuf = buf;
5596                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5597                         if (oldbuf)
5598                         {
5599                                 if (bufchars)
5600                                         memcpy(buf, oldbuf, bufchars);
5601                                 Mem_Free(oldbuf);
5602                         }
5603                 }
5604                 if (strlen(line))
5605                 {
5606                         memcpy(buf + bufchars, line, strlen(line));
5607                         bufchars += strlen(line);
5608                 }
5609         }
5610         if (bufchars)
5611                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5612         if (buf)
5613                 Mem_Free(buf);
5614 }
5615
5616 void R_Shadow_LoadLightsFile(void)
5617 {
5618         int n, a, style;
5619         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5620         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5621         if (cl.worldmodel == NULL)
5622         {
5623                 Con_Print("No map loaded.\n");
5624                 return;
5625         }
5626         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5627         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5628         if (lightsstring)
5629         {
5630                 s = lightsstring;
5631                 n = 0;
5632                 while (*s)
5633                 {
5634                         t = s;
5635                         while (*s && *s != '\n' && *s != '\r')
5636                                 s++;
5637                         if (!*s)
5638                                 break;
5639                         tempchar = *s;
5640                         *s = 0;
5641                         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);
5642                         *s = tempchar;
5643                         if (a < 14)
5644                         {
5645                                 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);
5646                                 break;
5647                         }
5648                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5649                         radius = bound(15, radius, 4096);
5650                         VectorScale(color, (2.0f / (8388608.0f)), color);
5651                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5652                         if (*s == '\r')
5653                                 s++;
5654                         if (*s == '\n')
5655                                 s++;
5656                         n++;
5657                 }
5658                 if (*s)
5659                         Con_Printf("invalid lights file \"%s\"\n", name);
5660                 Mem_Free(lightsstring);
5661         }
5662 }
5663
5664 // tyrlite/hmap2 light types in the delay field
5665 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5666
5667 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5668 {
5669         int entnum;
5670         int style;
5671         int islight;
5672         int skin;
5673         int pflags;
5674         //int effects;
5675         int type;
5676         int n;
5677         char *entfiledata;
5678         const char *data;
5679         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5680         char key[256], value[MAX_INPUTLINE];
5681
5682         if (cl.worldmodel == NULL)
5683         {
5684                 Con_Print("No map loaded.\n");
5685                 return;
5686         }
5687         // try to load a .ent file first
5688         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5689         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5690         // and if that is not found, fall back to the bsp file entity string
5691         if (!data)
5692                 data = cl.worldmodel->brush.entities;
5693         if (!data)
5694                 return;
5695         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5696         {
5697                 type = LIGHTTYPE_MINUSX;
5698                 origin[0] = origin[1] = origin[2] = 0;
5699                 originhack[0] = originhack[1] = originhack[2] = 0;
5700                 angles[0] = angles[1] = angles[2] = 0;
5701                 color[0] = color[1] = color[2] = 1;
5702                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5703                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5704                 fadescale = 1;
5705                 lightscale = 1;
5706                 style = 0;
5707                 skin = 0;
5708                 pflags = 0;
5709                 //effects = 0;
5710                 islight = false;
5711                 while (1)
5712                 {
5713                         if (!COM_ParseToken_Simple(&data, false, false))
5714                                 break; // error
5715                         if (com_token[0] == '}')
5716                                 break; // end of entity
5717                         if (com_token[0] == '_')
5718                                 strlcpy(key, com_token + 1, sizeof(key));
5719                         else
5720                                 strlcpy(key, com_token, sizeof(key));
5721                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5722                                 key[strlen(key)-1] = 0;
5723                         if (!COM_ParseToken_Simple(&data, false, false))
5724                                 break; // error
5725                         strlcpy(value, com_token, sizeof(value));
5726
5727                         // now that we have the key pair worked out...
5728                         if (!strcmp("light", key))
5729                         {
5730                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5731                                 if (n == 1)
5732                                 {
5733                                         // quake
5734                                         light[0] = vec[0] * (1.0f / 256.0f);
5735                                         light[1] = vec[0] * (1.0f / 256.0f);
5736                                         light[2] = vec[0] * (1.0f / 256.0f);
5737                                         light[3] = vec[0];
5738                                 }
5739                                 else if (n == 4)
5740                                 {
5741                                         // halflife
5742                                         light[0] = vec[0] * (1.0f / 255.0f);
5743                                         light[1] = vec[1] * (1.0f / 255.0f);
5744                                         light[2] = vec[2] * (1.0f / 255.0f);
5745                                         light[3] = vec[3];
5746                                 }
5747                         }
5748                         else if (!strcmp("delay", key))
5749                                 type = atoi(value);
5750                         else if (!strcmp("origin", key))
5751                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5752                         else if (!strcmp("angle", key))
5753                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5754                         else if (!strcmp("angles", key))
5755                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5756                         else if (!strcmp("color", key))
5757                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5758                         else if (!strcmp("wait", key))
5759                                 fadescale = atof(value);
5760                         else if (!strcmp("classname", key))
5761                         {
5762                                 if (!strncmp(value, "light", 5))
5763                                 {
5764                                         islight = true;
5765                                         if (!strcmp(value, "light_fluoro"))
5766                                         {
5767                                                 originhack[0] = 0;
5768                                                 originhack[1] = 0;
5769                                                 originhack[2] = 0;
5770                                                 overridecolor[0] = 1;
5771                                                 overridecolor[1] = 1;
5772                                                 overridecolor[2] = 1;
5773                                         }
5774                                         if (!strcmp(value, "light_fluorospark"))
5775                                         {
5776                                                 originhack[0] = 0;
5777                                                 originhack[1] = 0;
5778                                                 originhack[2] = 0;
5779                                                 overridecolor[0] = 1;
5780                                                 overridecolor[1] = 1;
5781                                                 overridecolor[2] = 1;
5782                                         }
5783                                         if (!strcmp(value, "light_globe"))
5784                                         {
5785                                                 originhack[0] = 0;
5786                                                 originhack[1] = 0;
5787                                                 originhack[2] = 0;
5788                                                 overridecolor[0] = 1;
5789                                                 overridecolor[1] = 0.8;
5790                                                 overridecolor[2] = 0.4;
5791                                         }
5792                                         if (!strcmp(value, "light_flame_large_yellow"))
5793                                         {
5794                                                 originhack[0] = 0;
5795                                                 originhack[1] = 0;
5796                                                 originhack[2] = 0;
5797                                                 overridecolor[0] = 1;
5798                                                 overridecolor[1] = 0.5;
5799                                                 overridecolor[2] = 0.1;
5800                                         }
5801                                         if (!strcmp(value, "light_flame_small_yellow"))
5802                                         {
5803                                                 originhack[0] = 0;
5804                                                 originhack[1] = 0;
5805                                                 originhack[2] = 0;
5806                                                 overridecolor[0] = 1;
5807                                                 overridecolor[1] = 0.5;
5808                                                 overridecolor[2] = 0.1;
5809                                         }
5810                                         if (!strcmp(value, "light_torch_small_white"))
5811                                         {
5812                                                 originhack[0] = 0;
5813                                                 originhack[1] = 0;
5814                                                 originhack[2] = 0;
5815                                                 overridecolor[0] = 1;
5816                                                 overridecolor[1] = 0.5;
5817                                                 overridecolor[2] = 0.1;
5818                                         }
5819                                         if (!strcmp(value, "light_torch_small_walltorch"))
5820                                         {
5821                                                 originhack[0] = 0;
5822                                                 originhack[1] = 0;
5823                                                 originhack[2] = 0;
5824                                                 overridecolor[0] = 1;
5825                                                 overridecolor[1] = 0.5;
5826                                                 overridecolor[2] = 0.1;
5827                                         }
5828                                 }
5829                         }
5830                         else if (!strcmp("style", key))
5831                                 style = atoi(value);
5832                         else if (!strcmp("skin", key))
5833                                 skin = (int)atof(value);
5834                         else if (!strcmp("pflags", key))
5835                                 pflags = (int)atof(value);
5836                         //else if (!strcmp("effects", key))
5837                         //      effects = (int)atof(value);
5838                         else if (cl.worldmodel->type == mod_brushq3)
5839                         {
5840                                 if (!strcmp("scale", key))
5841                                         lightscale = atof(value);
5842                                 if (!strcmp("fade", key))
5843                                         fadescale = atof(value);
5844                         }
5845                 }
5846                 if (!islight)
5847                         continue;
5848                 if (lightscale <= 0)
5849                         lightscale = 1;
5850                 if (fadescale <= 0)
5851                         fadescale = 1;
5852                 if (color[0] == color[1] && color[0] == color[2])
5853                 {
5854                         color[0] *= overridecolor[0];
5855                         color[1] *= overridecolor[1];
5856                         color[2] *= overridecolor[2];
5857                 }
5858                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5859                 color[0] = color[0] * light[0];
5860                 color[1] = color[1] * light[1];
5861                 color[2] = color[2] * light[2];
5862                 switch (type)
5863                 {
5864                 case LIGHTTYPE_MINUSX:
5865                         break;
5866                 case LIGHTTYPE_RECIPX:
5867                         radius *= 2;
5868                         VectorScale(color, (1.0f / 16.0f), color);
5869                         break;
5870                 case LIGHTTYPE_RECIPXX:
5871                         radius *= 2;
5872                         VectorScale(color, (1.0f / 16.0f), color);
5873                         break;
5874                 default:
5875                 case LIGHTTYPE_NONE:
5876                         break;
5877                 case LIGHTTYPE_SUN:
5878                         break;
5879                 case LIGHTTYPE_MINUSXX:
5880                         break;
5881                 }
5882                 VectorAdd(origin, originhack, origin);
5883                 if (radius >= 1)
5884                         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);
5885         }
5886         if (entfiledata)
5887                 Mem_Free(entfiledata);
5888 }
5889
5890
5891 void R_Shadow_SetCursorLocationForView(void)
5892 {
5893         vec_t dist, push;
5894         vec3_t dest, endpos;
5895         trace_t trace;
5896         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5897         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5898         if (trace.fraction < 1)
5899         {
5900                 dist = trace.fraction * r_editlights_cursordistance.value;
5901                 push = r_editlights_cursorpushback.value;
5902                 if (push > dist)
5903                         push = dist;
5904                 push = -push;
5905                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5906                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5907         }
5908         else
5909         {
5910                 VectorClear( endpos );
5911         }
5912         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5913         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5914         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5915 }
5916
5917 void R_Shadow_UpdateWorldLightSelection(void)
5918 {
5919         if (r_editlights.integer)
5920         {
5921                 R_Shadow_SetCursorLocationForView();
5922                 R_Shadow_SelectLightInView();
5923         }
5924         else
5925                 R_Shadow_SelectLight(NULL);
5926 }
5927
5928 void R_Shadow_EditLights_Clear_f(void)
5929 {
5930         R_Shadow_ClearWorldLights();
5931 }
5932
5933 void R_Shadow_EditLights_Reload_f(void)
5934 {
5935         if (!cl.worldmodel)
5936                 return;
5937         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5938         R_Shadow_ClearWorldLights();
5939         R_Shadow_LoadWorldLights();
5940         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5941         {
5942                 R_Shadow_LoadLightsFile();
5943                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5944                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5945         }
5946 }
5947
5948 void R_Shadow_EditLights_Save_f(void)
5949 {
5950         if (!cl.worldmodel)
5951                 return;
5952         R_Shadow_SaveWorldLights();
5953 }
5954
5955 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5956 {
5957         R_Shadow_ClearWorldLights();
5958         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5959 }
5960
5961 void R_Shadow_EditLights_ImportLightsFile_f(void)
5962 {
5963         R_Shadow_ClearWorldLights();
5964         R_Shadow_LoadLightsFile();
5965 }
5966
5967 void R_Shadow_EditLights_Spawn_f(void)
5968 {
5969         vec3_t color;
5970         if (!r_editlights.integer)
5971         {
5972                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5973                 return;
5974         }
5975         if (Cmd_Argc() != 1)
5976         {
5977                 Con_Print("r_editlights_spawn does not take parameters\n");
5978                 return;
5979         }
5980         color[0] = color[1] = color[2] = 1;
5981         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5982 }
5983
5984 void R_Shadow_EditLights_Edit_f(void)
5985 {
5986         vec3_t origin, angles, color;
5987         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5988         int style, shadows, flags, normalmode, realtimemode;
5989         char cubemapname[MAX_INPUTLINE];
5990         if (!r_editlights.integer)
5991         {
5992                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5993                 return;
5994         }
5995         if (!r_shadow_selectedlight)
5996         {
5997                 Con_Print("No selected light.\n");
5998                 return;
5999         }
6000         VectorCopy(r_shadow_selectedlight->origin, origin);
6001         VectorCopy(r_shadow_selectedlight->angles, angles);
6002         VectorCopy(r_shadow_selectedlight->color, color);
6003         radius = r_shadow_selectedlight->radius;
6004         style = r_shadow_selectedlight->style;
6005         if (r_shadow_selectedlight->cubemapname)
6006                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6007         else
6008                 cubemapname[0] = 0;
6009         shadows = r_shadow_selectedlight->shadow;
6010         corona = r_shadow_selectedlight->corona;
6011         coronasizescale = r_shadow_selectedlight->coronasizescale;
6012         ambientscale = r_shadow_selectedlight->ambientscale;
6013         diffusescale = r_shadow_selectedlight->diffusescale;
6014         specularscale = r_shadow_selectedlight->specularscale;
6015         flags = r_shadow_selectedlight->flags;
6016         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6017         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6018         if (!strcmp(Cmd_Argv(1), "origin"))
6019         {
6020                 if (Cmd_Argc() != 5)
6021                 {
6022                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6023                         return;
6024                 }
6025                 origin[0] = atof(Cmd_Argv(2));
6026                 origin[1] = atof(Cmd_Argv(3));
6027                 origin[2] = atof(Cmd_Argv(4));
6028         }
6029         else if (!strcmp(Cmd_Argv(1), "originx"))
6030         {
6031                 if (Cmd_Argc() != 3)
6032                 {
6033                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6034                         return;
6035                 }
6036                 origin[0] = atof(Cmd_Argv(2));
6037         }
6038         else if (!strcmp(Cmd_Argv(1), "originy"))
6039         {
6040                 if (Cmd_Argc() != 3)
6041                 {
6042                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6043                         return;
6044                 }
6045                 origin[1] = atof(Cmd_Argv(2));
6046         }
6047         else if (!strcmp(Cmd_Argv(1), "originz"))
6048         {
6049                 if (Cmd_Argc() != 3)
6050                 {
6051                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6052                         return;
6053                 }
6054                 origin[2] = atof(Cmd_Argv(2));
6055         }
6056         else if (!strcmp(Cmd_Argv(1), "move"))
6057         {
6058                 if (Cmd_Argc() != 5)
6059                 {
6060                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6061                         return;
6062                 }
6063                 origin[0] += atof(Cmd_Argv(2));
6064                 origin[1] += atof(Cmd_Argv(3));
6065                 origin[2] += atof(Cmd_Argv(4));
6066         }
6067         else if (!strcmp(Cmd_Argv(1), "movex"))
6068         {
6069                 if (Cmd_Argc() != 3)
6070                 {
6071                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6072                         return;
6073                 }
6074                 origin[0] += atof(Cmd_Argv(2));
6075         }
6076         else if (!strcmp(Cmd_Argv(1), "movey"))
6077         {
6078                 if (Cmd_Argc() != 3)
6079                 {
6080                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6081                         return;
6082                 }
6083                 origin[1] += atof(Cmd_Argv(2));
6084         }
6085         else if (!strcmp(Cmd_Argv(1), "movez"))
6086         {
6087                 if (Cmd_Argc() != 3)
6088                 {
6089                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6090                         return;
6091                 }
6092                 origin[2] += atof(Cmd_Argv(2));
6093         }
6094         else if (!strcmp(Cmd_Argv(1), "angles"))
6095         {
6096                 if (Cmd_Argc() != 5)
6097                 {
6098                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6099                         return;
6100                 }
6101                 angles[0] = atof(Cmd_Argv(2));
6102                 angles[1] = atof(Cmd_Argv(3));
6103                 angles[2] = atof(Cmd_Argv(4));
6104         }
6105         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6106         {
6107                 if (Cmd_Argc() != 3)
6108                 {
6109                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6110                         return;
6111                 }
6112                 angles[0] = atof(Cmd_Argv(2));
6113         }
6114         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6115         {
6116                 if (Cmd_Argc() != 3)
6117                 {
6118                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6119                         return;
6120                 }
6121                 angles[1] = atof(Cmd_Argv(2));
6122         }
6123         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6124         {
6125                 if (Cmd_Argc() != 3)
6126                 {
6127                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6128                         return;
6129                 }
6130                 angles[2] = atof(Cmd_Argv(2));
6131         }
6132         else if (!strcmp(Cmd_Argv(1), "color"))
6133         {
6134                 if (Cmd_Argc() != 5)
6135                 {
6136                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6137                         return;
6138                 }
6139                 color[0] = atof(Cmd_Argv(2));
6140                 color[1] = atof(Cmd_Argv(3));
6141                 color[2] = atof(Cmd_Argv(4));
6142         }
6143         else if (!strcmp(Cmd_Argv(1), "radius"))
6144         {
6145                 if (Cmd_Argc() != 3)
6146                 {
6147                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6148                         return;
6149                 }
6150                 radius = atof(Cmd_Argv(2));
6151         }
6152         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6153         {
6154                 if (Cmd_Argc() == 3)
6155                 {
6156                         double scale = atof(Cmd_Argv(2));
6157                         color[0] *= scale;
6158                         color[1] *= scale;
6159                         color[2] *= scale;
6160                 }
6161                 else
6162                 {
6163                         if (Cmd_Argc() != 5)
6164                         {
6165                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
6166                                 return;
6167                         }
6168                         color[0] *= atof(Cmd_Argv(2));
6169                         color[1] *= atof(Cmd_Argv(3));
6170                         color[2] *= atof(Cmd_Argv(4));
6171                 }
6172         }
6173         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6174         {
6175                 if (Cmd_Argc() != 3)
6176                 {
6177                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6178                         return;
6179                 }
6180                 radius *= atof(Cmd_Argv(2));
6181         }
6182         else if (!strcmp(Cmd_Argv(1), "style"))
6183         {
6184                 if (Cmd_Argc() != 3)
6185                 {
6186                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6187                         return;
6188                 }
6189                 style = atoi(Cmd_Argv(2));
6190         }
6191         else if (!strcmp(Cmd_Argv(1), "cubemap"))
6192         {
6193                 if (Cmd_Argc() > 3)
6194                 {
6195                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6196                         return;
6197                 }
6198                 if (Cmd_Argc() == 3)
6199                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6200                 else
6201                         cubemapname[0] = 0;
6202         }
6203         else if (!strcmp(Cmd_Argv(1), "shadows"))
6204         {
6205                 if (Cmd_Argc() != 3)
6206                 {
6207                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6208                         return;
6209                 }
6210                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6211         }
6212         else if (!strcmp(Cmd_Argv(1), "corona"))
6213         {
6214                 if (Cmd_Argc() != 3)
6215                 {
6216                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6217                         return;
6218                 }
6219                 corona = atof(Cmd_Argv(2));
6220         }
6221         else if (!strcmp(Cmd_Argv(1), "coronasize"))
6222         {
6223                 if (Cmd_Argc() != 3)
6224                 {
6225                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6226                         return;
6227                 }
6228                 coronasizescale = atof(Cmd_Argv(2));
6229         }
6230         else if (!strcmp(Cmd_Argv(1), "ambient"))
6231         {
6232                 if (Cmd_Argc() != 3)
6233                 {
6234                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6235                         return;
6236                 }
6237                 ambientscale = atof(Cmd_Argv(2));
6238         }
6239         else if (!strcmp(Cmd_Argv(1), "diffuse"))
6240         {
6241                 if (Cmd_Argc() != 3)
6242                 {
6243                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6244                         return;
6245                 }
6246                 diffusescale = atof(Cmd_Argv(2));
6247         }
6248         else if (!strcmp(Cmd_Argv(1), "specular"))
6249         {
6250                 if (Cmd_Argc() != 3)
6251                 {
6252                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6253                         return;
6254                 }
6255                 specularscale = atof(Cmd_Argv(2));
6256         }
6257         else if (!strcmp(Cmd_Argv(1), "normalmode"))
6258         {
6259                 if (Cmd_Argc() != 3)
6260                 {
6261                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6262                         return;
6263                 }
6264                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6265         }
6266         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6267         {
6268                 if (Cmd_Argc() != 3)
6269                 {
6270                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6271                         return;
6272                 }
6273                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6274         }
6275         else
6276         {
6277                 Con_Print("usage: r_editlights_edit [property] [value]\n");
6278                 Con_Print("Selected light's properties:\n");
6279                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6280                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6281                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6282                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
6283                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
6284                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
6285                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6286                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
6287                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
6288                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
6289                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
6290                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
6291                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6292                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6293                 return;
6294         }
6295         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6296         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6297 }
6298
6299 void R_Shadow_EditLights_EditAll_f(void)
6300 {
6301         size_t lightindex;
6302         dlight_t *light, *oldselected;
6303         size_t range;
6304
6305         if (!r_editlights.integer)
6306         {
6307                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6308                 return;
6309         }
6310
6311         oldselected = r_shadow_selectedlight;
6312         // EditLights doesn't seem to have a "remove" command or something so:
6313         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6314         for (lightindex = 0;lightindex < range;lightindex++)
6315         {
6316                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6317                 if (!light)
6318                         continue;
6319                 R_Shadow_SelectLight(light);
6320                 R_Shadow_EditLights_Edit_f();
6321         }
6322         // return to old selected (to not mess editing once selection is locked)
6323         R_Shadow_SelectLight(oldselected);
6324 }
6325
6326 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6327 {
6328         int lightnumber, lightcount;
6329         size_t lightindex, range;
6330         dlight_t *light;
6331         float x, y;
6332         char temp[256];
6333         if (!r_editlights.integer)
6334                 return;
6335         x = vid_conwidth.value - 240;
6336         y = 5;
6337         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6338         lightnumber = -1;
6339         lightcount = 0;
6340         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6341         for (lightindex = 0;lightindex < range;lightindex++)
6342         {
6343                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6344                 if (!light)
6345                         continue;
6346                 if (light == r_shadow_selectedlight)
6347                         lightnumber = lightindex;
6348                 lightcount++;
6349         }
6350         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, FONT_DEFAULT);y += 8;
6351         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, FONT_DEFAULT);y += 8;
6352         y += 8;
6353         if (r_shadow_selectedlight == NULL)
6354                 return;
6355         dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
6356         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, FONT_DEFAULT);y += 8;
6357         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, FONT_DEFAULT);y += 8;
6358         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, FONT_DEFAULT);y += 8;
6359         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, FONT_DEFAULT);y += 8;
6360         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, FONT_DEFAULT);y += 8;
6361         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, FONT_DEFAULT);y += 8;
6362         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, FONT_DEFAULT);y += 8;
6363         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, FONT_DEFAULT);y += 8;
6364         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, FONT_DEFAULT);y += 8;
6365         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, FONT_DEFAULT);y += 8;
6366         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, FONT_DEFAULT);y += 8;
6367         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, FONT_DEFAULT);y += 8;
6368         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, FONT_DEFAULT);y += 8;
6369         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, FONT_DEFAULT);y += 8;
6370 }
6371
6372 void R_Shadow_EditLights_ToggleShadow_f(void)
6373 {
6374         if (!r_editlights.integer)
6375         {
6376                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6377                 return;
6378         }
6379         if (!r_shadow_selectedlight)
6380         {
6381                 Con_Print("No selected light.\n");
6382                 return;
6383         }
6384         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);
6385 }
6386
6387 void R_Shadow_EditLights_ToggleCorona_f(void)
6388 {
6389         if (!r_editlights.integer)
6390         {
6391                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6392                 return;
6393         }
6394         if (!r_shadow_selectedlight)
6395         {
6396                 Con_Print("No selected light.\n");
6397                 return;
6398         }
6399         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);
6400 }
6401
6402 void R_Shadow_EditLights_Remove_f(void)
6403 {
6404         if (!r_editlights.integer)
6405         {
6406                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
6407                 return;
6408         }
6409         if (!r_shadow_selectedlight)
6410         {
6411                 Con_Print("No selected light.\n");
6412                 return;
6413         }
6414         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6415         r_shadow_selectedlight = NULL;
6416 }
6417
6418 void R_Shadow_EditLights_Help_f(void)
6419 {
6420         Con_Print(
6421 "Documentation on r_editlights system:\n"
6422 "Settings:\n"
6423 "r_editlights : enable/disable editing mode\n"
6424 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6425 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6426 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6427 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6428 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6429 "Commands:\n"
6430 "r_editlights_help : this help\n"
6431 "r_editlights_clear : remove all lights\n"
6432 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6433 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6434 "r_editlights_save : save to .rtlights file\n"
6435 "r_editlights_spawn : create a light with default settings\n"
6436 "r_editlights_edit command : edit selected light - more documentation below\n"
6437 "r_editlights_remove : remove selected light\n"
6438 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6439 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6440 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6441 "Edit commands:\n"
6442 "origin x y z : set light location\n"
6443 "originx x: set x component of light location\n"
6444 "originy y: set y component of light location\n"
6445 "originz z: set z component of light location\n"
6446 "move x y z : adjust light location\n"
6447 "movex x: adjust x component of light location\n"
6448 "movey y: adjust y component of light location\n"
6449 "movez z: adjust z component of light location\n"
6450 "angles x y z : set light angles\n"
6451 "anglesx x: set x component of light angles\n"
6452 "anglesy y: set y component of light angles\n"
6453 "anglesz z: set z component of light angles\n"
6454 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6455 "radius radius : set radius (size) of light\n"
6456 "colorscale grey : multiply color of light (1 does nothing)\n"
6457 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6458 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6459 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6460 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6461 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6462 "shadows 1/0 : turn on/off shadows\n"
6463 "corona n : set corona intensity\n"
6464 "coronasize n : set corona size (0-1)\n"
6465 "ambient n : set ambient intensity (0-1)\n"
6466 "diffuse n : set diffuse intensity (0-1)\n"
6467 "specular n : set specular intensity (0-1)\n"
6468 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6469 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6470 "<nothing> : print light properties to console\n"
6471         );
6472 }
6473
6474 void R_Shadow_EditLights_CopyInfo_f(void)
6475 {
6476         if (!r_editlights.integer)
6477         {
6478                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6479                 return;
6480         }
6481         if (!r_shadow_selectedlight)
6482         {
6483                 Con_Print("No selected light.\n");
6484                 return;
6485         }
6486         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6487         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6488         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6489         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6490         if (r_shadow_selectedlight->cubemapname)
6491                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6492         else
6493                 r_shadow_bufferlight.cubemapname[0] = 0;
6494         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6495         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6496         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6497         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6498         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6499         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6500         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6501 }
6502
6503 void R_Shadow_EditLights_PasteInfo_f(void)
6504 {
6505         if (!r_editlights.integer)
6506         {
6507                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6508                 return;
6509         }
6510         if (!r_shadow_selectedlight)
6511         {
6512                 Con_Print("No selected light.\n");
6513                 return;
6514         }
6515         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);
6516 }
6517
6518 void R_Shadow_EditLights_Lock_f(void)
6519 {
6520         if (!r_editlights.integer)
6521         {
6522                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6523                 return;
6524         }
6525         if (r_editlights_lockcursor)
6526         {
6527                 r_editlights_lockcursor = false;
6528                 return;
6529         }
6530         if (!r_shadow_selectedlight)
6531         {
6532                 Con_Print("No selected light to lock on.\n");
6533                 return;
6534         }
6535         r_editlights_lockcursor = true;
6536 }
6537
6538 void R_Shadow_EditLights_Init(void)
6539 {
6540         Cvar_RegisterVariable(&r_editlights);
6541         Cvar_RegisterVariable(&r_editlights_cursordistance);
6542         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6543         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6544         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6545         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6546         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6547         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6548         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)");
6549         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6550         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6551         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6552         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)");
6553         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6554         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6555         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6556         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6557         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6558         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6559         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)");
6560         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6561 }
6562
6563
6564
6565 /*
6566 =============================================================================
6567
6568 LIGHT SAMPLING
6569
6570 =============================================================================
6571 */
6572
6573 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6574 {
6575         int i, numlights, flag;
6576         rtlight_t *light;
6577         dlight_t *dlight;
6578         float relativepoint[3];
6579         float color[3];
6580         float dir[3];
6581         float dist;
6582         float dist2;
6583         float intensity;
6584         float sample[5*3];
6585         float lightradius2;
6586
6587         if (r_fullbright.integer)
6588         {
6589                 VectorSet(ambient, 1, 1, 1);
6590                 VectorClear(diffuse);
6591                 VectorClear(lightdir);
6592                 return;
6593         }
6594
6595         if (flags & LP_LIGHTMAP)
6596         {
6597                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6598                 VectorClear(diffuse);
6599                 VectorClear(lightdir);
6600                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6601                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6602                 return;
6603         }
6604
6605         memset(sample, 0, sizeof(sample));
6606         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6607
6608         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6609         {
6610                 vec3_t tempambient;
6611                 VectorClear(tempambient);
6612                 VectorClear(color);
6613                 VectorClear(relativepoint);
6614                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6615                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6616                 VectorScale(color, r_refdef.lightmapintensity, color);
6617                 VectorAdd(sample, tempambient, sample);
6618                 VectorMA(sample    , 0.5f            , color, sample    );
6619                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6620                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6621                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6622                 // calculate a weighted average light direction as well
6623                 intensity = VectorLength(color);
6624                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6625         }
6626
6627         if (flags & LP_RTWORLD)
6628         {
6629                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6630                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6631                 for (i = 0; i < numlights; i++)
6632                 {
6633                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6634                         if (!dlight)
6635                                 continue;
6636                         light = &dlight->rtlight;
6637                         if (!(light->flags & flag))
6638                                 continue;
6639                         // sample
6640                         lightradius2 = light->radius * light->radius;
6641                         VectorSubtract(light->shadoworigin, p, relativepoint);
6642                         dist2 = VectorLength2(relativepoint);
6643                         if (dist2 >= lightradius2)
6644                                 continue;
6645                         dist = sqrt(dist2) / light->radius;
6646                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6647                         if (intensity <= 0.0f)
6648                                 continue;
6649                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6650                                 continue;
6651                         // scale down intensity to add to both ambient and diffuse
6652                         //intensity *= 0.5f;
6653                         VectorNormalize(relativepoint);
6654                         VectorScale(light->currentcolor, intensity, color);
6655                         VectorMA(sample    , 0.5f            , color, sample    );
6656                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6657                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6658                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6659                         // calculate a weighted average light direction as well
6660                         intensity *= VectorLength(color);
6661                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6662                 }
6663         }
6664
6665         if (flags & LP_DYNLIGHT)
6666         {
6667                 // sample dlights
6668                 for (i = 0;i < r_refdef.scene.numlights;i++)
6669                 {
6670                         light = r_refdef.scene.lights[i];
6671                         // sample
6672                         lightradius2 = light->radius * light->radius;
6673                         VectorSubtract(light->shadoworigin, p, relativepoint);
6674                         dist2 = VectorLength2(relativepoint);
6675                         if (dist2 >= lightradius2)
6676                                 continue;
6677                         dist = sqrt(dist2) / light->radius;
6678                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6679                         if (intensity <= 0.0f)
6680                                 continue;
6681                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6682                                 continue;
6683                         // scale down intensity to add to both ambient and diffuse
6684                         //intensity *= 0.5f;
6685                         VectorNormalize(relativepoint);
6686                         VectorScale(light->currentcolor, intensity, color);
6687                         VectorMA(sample    , 0.5f            , color, sample    );
6688                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6689                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6690                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6691                         // calculate a weighted average light direction as well
6692                         intensity *= VectorLength(color);
6693                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6694                 }
6695         }
6696
6697         // calculate the direction we'll use to reduce the sample to a directional light source
6698         VectorCopy(sample + 12, dir);
6699         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6700         VectorNormalize(dir);
6701         // extract the diffuse color along the chosen direction and scale it
6702         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6703         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6704         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6705         // subtract some of diffuse from ambient
6706         VectorMA(sample, -0.333f, diffuse, ambient);
6707         // store the normalized lightdir
6708         VectorCopy(dir, lightdir);
6709 }