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