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