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