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