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