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