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