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