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