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