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