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