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