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