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