]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
added a FIXME comment - R_CompleteLightPoint should count bouncegrid
[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 extern 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_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
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_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
263
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
266
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
269
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
271
272 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"};
273 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"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 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"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "4", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
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 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(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
445                                         r_shadow_shadowmappcf = 1;
446                                 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) 
447                                 {
448                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
449                                         r_shadow_shadowmappcf = 1;
450                                 }
451                                 else if(strstr(gl_vendor, "ATI")) 
452                                         r_shadow_shadowmappcf = 1;
453                                 else 
454                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
455                         }
456                         else 
457                         {
458                                 switch (r_shadow_shadowmapfilterquality)
459                                 {
460                                 case 1:
461                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
462                                         break;
463                                 case 2:
464                                         r_shadow_shadowmapsampler = vid.support.arb_shadow;
465                                         r_shadow_shadowmappcf = 1;
466                                         break;
467                                 case 3:
468                                         r_shadow_shadowmappcf = 1;
469                                         break;
470                                 case 4:
471                                         r_shadow_shadowmappcf = 2;
472                                         break;
473                                 }
474                         }
475                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
476                         break;
477                 case RENDERPATH_D3D9:
478                 case RENDERPATH_D3D10:
479                 case RENDERPATH_D3D11:
480                 case RENDERPATH_SOFT:
481                         r_shadow_shadowmapsampler = false;
482                         r_shadow_shadowmappcf = 1;
483                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
484                         break;
485                 case RENDERPATH_GL11:
486                 case RENDERPATH_GL13:
487                 case RENDERPATH_GLES1:
488                 case RENDERPATH_GLES2:
489                         break;
490                 }
491         }
492 }
493
494 qboolean R_Shadow_ShadowMappingEnabled(void)
495 {
496         switch (r_shadow_shadowmode)
497         {
498         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
499                 return true;
500         default:
501                 return false;
502         }
503 }
504
505 void R_Shadow_FreeShadowMaps(void)
506 {
507         R_Shadow_SetShadowMode();
508
509         R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
510
511         r_shadow_fbo2d = 0;
512
513         if (r_shadow_shadowmap2dtexture)
514                 R_FreeTexture(r_shadow_shadowmap2dtexture);
515         r_shadow_shadowmap2dtexture = NULL;
516
517         if (r_shadow_shadowmap2dcolortexture)
518                 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
519         r_shadow_shadowmap2dcolortexture = NULL;
520
521         if (r_shadow_shadowmapvsdcttexture)
522                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
523         r_shadow_shadowmapvsdcttexture = NULL;
524 }
525
526 void r_shadow_start(void)
527 {
528         // allocate vertex processing arrays
529         r_shadow_bouncegridpixels = NULL;
530         r_shadow_bouncegridhighpixels = NULL;
531         r_shadow_bouncegridnumpixels = 0;
532         r_shadow_bouncegridtexture = NULL;
533         r_shadow_bouncegriddirectional = false;
534         r_shadow_attenuationgradienttexture = NULL;
535         r_shadow_attenuation2dtexture = NULL;
536         r_shadow_attenuation3dtexture = NULL;
537         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
538         r_shadow_shadowmap2dtexture = NULL;
539         r_shadow_shadowmap2dcolortexture = NULL;
540         r_shadow_shadowmapvsdcttexture = NULL;
541         r_shadow_shadowmapmaxsize = 0;
542         r_shadow_shadowmapsize = 0;
543         r_shadow_shadowmaplod = 0;
544         r_shadow_shadowmapfilterquality = -1;
545         r_shadow_shadowmapdepthbits = 0;
546         r_shadow_shadowmapvsdct = false;
547         r_shadow_shadowmapsampler = false;
548         r_shadow_shadowmappcf = 0;
549         r_shadow_fbo2d = 0;
550
551         R_Shadow_FreeShadowMaps();
552
553         r_shadow_texturepool = NULL;
554         r_shadow_filters_texturepool = NULL;
555         R_Shadow_ValidateCvars();
556         R_Shadow_MakeTextures();
557         maxshadowtriangles = 0;
558         shadowelements = NULL;
559         maxshadowvertices = 0;
560         shadowvertex3f = NULL;
561         maxvertexupdate = 0;
562         vertexupdate = NULL;
563         vertexremap = NULL;
564         vertexupdatenum = 0;
565         maxshadowmark = 0;
566         numshadowmark = 0;
567         shadowmark = NULL;
568         shadowmarklist = NULL;
569         shadowmarkcount = 0;
570         maxshadowsides = 0;
571         numshadowsides = 0;
572         shadowsides = NULL;
573         shadowsideslist = NULL;
574         r_shadow_buffer_numleafpvsbytes = 0;
575         r_shadow_buffer_visitingleafpvs = NULL;
576         r_shadow_buffer_leafpvs = NULL;
577         r_shadow_buffer_leaflist = NULL;
578         r_shadow_buffer_numsurfacepvsbytes = 0;
579         r_shadow_buffer_surfacepvs = NULL;
580         r_shadow_buffer_surfacelist = NULL;
581         r_shadow_buffer_surfacesides = NULL;
582         r_shadow_buffer_numshadowtrispvsbytes = 0;
583         r_shadow_buffer_shadowtrispvs = NULL;
584         r_shadow_buffer_numlighttrispvsbytes = 0;
585         r_shadow_buffer_lighttrispvs = NULL;
586
587         r_shadow_usingdeferredprepass = false;
588         r_shadow_prepass_width = r_shadow_prepass_height = 0;
589 }
590
591 static void R_Shadow_FreeDeferred(void);
592 void r_shadow_shutdown(void)
593 {
594         CHECKGLERROR
595         R_Shadow_UncompileWorldLights();
596
597         R_Shadow_FreeShadowMaps();
598
599         r_shadow_usingdeferredprepass = false;
600         if (r_shadow_prepass_width)
601                 R_Shadow_FreeDeferred();
602         r_shadow_prepass_width = r_shadow_prepass_height = 0;
603
604         CHECKGLERROR
605         r_shadow_bouncegridtexture = NULL;
606         r_shadow_bouncegridpixels = NULL;
607         r_shadow_bouncegridhighpixels = NULL;
608         r_shadow_bouncegridnumpixels = 0;
609         r_shadow_bouncegriddirectional = false;
610         r_shadow_attenuationgradienttexture = NULL;
611         r_shadow_attenuation2dtexture = NULL;
612         r_shadow_attenuation3dtexture = NULL;
613         R_FreeTexturePool(&r_shadow_texturepool);
614         R_FreeTexturePool(&r_shadow_filters_texturepool);
615         maxshadowtriangles = 0;
616         if (shadowelements)
617                 Mem_Free(shadowelements);
618         shadowelements = NULL;
619         if (shadowvertex3f)
620                 Mem_Free(shadowvertex3f);
621         shadowvertex3f = NULL;
622         maxvertexupdate = 0;
623         if (vertexupdate)
624                 Mem_Free(vertexupdate);
625         vertexupdate = NULL;
626         if (vertexremap)
627                 Mem_Free(vertexremap);
628         vertexremap = NULL;
629         vertexupdatenum = 0;
630         maxshadowmark = 0;
631         numshadowmark = 0;
632         if (shadowmark)
633                 Mem_Free(shadowmark);
634         shadowmark = NULL;
635         if (shadowmarklist)
636                 Mem_Free(shadowmarklist);
637         shadowmarklist = NULL;
638         shadowmarkcount = 0;
639         maxshadowsides = 0;
640         numshadowsides = 0;
641         if (shadowsides)
642                 Mem_Free(shadowsides);
643         shadowsides = NULL;
644         if (shadowsideslist)
645                 Mem_Free(shadowsideslist);
646         shadowsideslist = NULL;
647         r_shadow_buffer_numleafpvsbytes = 0;
648         if (r_shadow_buffer_visitingleafpvs)
649                 Mem_Free(r_shadow_buffer_visitingleafpvs);
650         r_shadow_buffer_visitingleafpvs = NULL;
651         if (r_shadow_buffer_leafpvs)
652                 Mem_Free(r_shadow_buffer_leafpvs);
653         r_shadow_buffer_leafpvs = NULL;
654         if (r_shadow_buffer_leaflist)
655                 Mem_Free(r_shadow_buffer_leaflist);
656         r_shadow_buffer_leaflist = NULL;
657         r_shadow_buffer_numsurfacepvsbytes = 0;
658         if (r_shadow_buffer_surfacepvs)
659                 Mem_Free(r_shadow_buffer_surfacepvs);
660         r_shadow_buffer_surfacepvs = NULL;
661         if (r_shadow_buffer_surfacelist)
662                 Mem_Free(r_shadow_buffer_surfacelist);
663         r_shadow_buffer_surfacelist = NULL;
664         if (r_shadow_buffer_surfacesides)
665                 Mem_Free(r_shadow_buffer_surfacesides);
666         r_shadow_buffer_surfacesides = NULL;
667         r_shadow_buffer_numshadowtrispvsbytes = 0;
668         if (r_shadow_buffer_shadowtrispvs)
669                 Mem_Free(r_shadow_buffer_shadowtrispvs);
670         r_shadow_buffer_numlighttrispvsbytes = 0;
671         if (r_shadow_buffer_lighttrispvs)
672                 Mem_Free(r_shadow_buffer_lighttrispvs);
673 }
674
675 void r_shadow_newmap(void)
676 {
677         if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
678         if (r_shadow_lightcorona)                 R_SkinFrame_MarkUsed(r_shadow_lightcorona);
679         if (r_editlights_sprcursor)               R_SkinFrame_MarkUsed(r_editlights_sprcursor);
680         if (r_editlights_sprlight)                R_SkinFrame_MarkUsed(r_editlights_sprlight);
681         if (r_editlights_sprnoshadowlight)        R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
682         if (r_editlights_sprcubemaplight)         R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
683         if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
684         if (r_editlights_sprselection)            R_SkinFrame_MarkUsed(r_editlights_sprselection);
685         if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
686                 R_Shadow_EditLights_Reload_f();
687 }
688
689 void R_Shadow_Init(void)
690 {
691         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
692         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
693         Cvar_RegisterVariable(&r_shadow_usebihculling);
694         Cvar_RegisterVariable(&r_shadow_usenormalmap);
695         Cvar_RegisterVariable(&r_shadow_debuglight);
696         Cvar_RegisterVariable(&r_shadow_deferred);
697         Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
698 //      Cvar_RegisterVariable(&r_shadow_deferred_fp);
699         Cvar_RegisterVariable(&r_shadow_gloss);
700         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
701         Cvar_RegisterVariable(&r_shadow_glossintensity);
702         Cvar_RegisterVariable(&r_shadow_glossexponent);
703         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
704         Cvar_RegisterVariable(&r_shadow_glossexact);
705         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
706         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
707         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
708         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
709         Cvar_RegisterVariable(&r_shadow_projectdistance);
710         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
711         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
712         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
713         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
714         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
715         Cvar_RegisterVariable(&r_shadow_realtime_world);
716         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
717         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
718         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
719         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
720         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
721         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
722         Cvar_RegisterVariable(&r_shadow_scissor);
723         Cvar_RegisterVariable(&r_shadow_shadowmapping);
724         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
725         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
726         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
727         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
728         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
729         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
730 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
731 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
732         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
733         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
734         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
735         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
736         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
737         Cvar_RegisterVariable(&r_shadow_sortsurfaces);
738         Cvar_RegisterVariable(&r_shadow_polygonfactor);
739         Cvar_RegisterVariable(&r_shadow_polygonoffset);
740         Cvar_RegisterVariable(&r_shadow_texture3d);
741         Cvar_RegisterVariable(&r_shadow_bouncegrid);
742         Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
743         Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
744         Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
745         Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
746         Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
747         Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
748         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
749         Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
750         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
751         Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
752         Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
753         Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
754         Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
755         Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
756         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
757         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
758         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
759         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
760         Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
761         Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
762         Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
763         Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
764         Cvar_RegisterVariable(&r_coronas);
765         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
766         Cvar_RegisterVariable(&r_coronas_occlusionquery);
767         Cvar_RegisterVariable(&gl_flashblend);
768         Cvar_RegisterVariable(&gl_ext_separatestencil);
769         Cvar_RegisterVariable(&gl_ext_stenciltwoside);
770         R_Shadow_EditLights_Init();
771         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
772         maxshadowtriangles = 0;
773         shadowelements = NULL;
774         maxshadowvertices = 0;
775         shadowvertex3f = NULL;
776         maxvertexupdate = 0;
777         vertexupdate = NULL;
778         vertexremap = NULL;
779         vertexupdatenum = 0;
780         maxshadowmark = 0;
781         numshadowmark = 0;
782         shadowmark = NULL;
783         shadowmarklist = NULL;
784         shadowmarkcount = 0;
785         maxshadowsides = 0;
786         numshadowsides = 0;
787         shadowsides = NULL;
788         shadowsideslist = NULL;
789         r_shadow_buffer_numleafpvsbytes = 0;
790         r_shadow_buffer_visitingleafpvs = NULL;
791         r_shadow_buffer_leafpvs = NULL;
792         r_shadow_buffer_leaflist = NULL;
793         r_shadow_buffer_numsurfacepvsbytes = 0;
794         r_shadow_buffer_surfacepvs = NULL;
795         r_shadow_buffer_surfacelist = NULL;
796         r_shadow_buffer_surfacesides = NULL;
797         r_shadow_buffer_shadowtrispvs = NULL;
798         r_shadow_buffer_lighttrispvs = NULL;
799         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
800 }
801
802 matrix4x4_t matrix_attenuationxyz =
803 {
804         {
805                 {0.5, 0.0, 0.0, 0.5},
806                 {0.0, 0.5, 0.0, 0.5},
807                 {0.0, 0.0, 0.5, 0.5},
808                 {0.0, 0.0, 0.0, 1.0}
809         }
810 };
811
812 matrix4x4_t matrix_attenuationz =
813 {
814         {
815                 {0.0, 0.0, 0.5, 0.5},
816                 {0.0, 0.0, 0.0, 0.5},
817                 {0.0, 0.0, 0.0, 0.5},
818                 {0.0, 0.0, 0.0, 1.0}
819         }
820 };
821
822 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
823 {
824         numvertices = ((numvertices + 255) & ~255) * vertscale;
825         numtriangles = ((numtriangles + 255) & ~255) * triscale;
826         // make sure shadowelements is big enough for this volume
827         if (maxshadowtriangles < numtriangles)
828         {
829                 maxshadowtriangles = numtriangles;
830                 if (shadowelements)
831                         Mem_Free(shadowelements);
832                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
833         }
834         // make sure shadowvertex3f is big enough for this volume
835         if (maxshadowvertices < numvertices)
836         {
837                 maxshadowvertices = numvertices;
838                 if (shadowvertex3f)
839                         Mem_Free(shadowvertex3f);
840                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
841         }
842 }
843
844 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
845 {
846         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
847         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
848         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
849         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
850         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
851         {
852                 if (r_shadow_buffer_visitingleafpvs)
853                         Mem_Free(r_shadow_buffer_visitingleafpvs);
854                 if (r_shadow_buffer_leafpvs)
855                         Mem_Free(r_shadow_buffer_leafpvs);
856                 if (r_shadow_buffer_leaflist)
857                         Mem_Free(r_shadow_buffer_leaflist);
858                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
859                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
860                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
861                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
862         }
863         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
864         {
865                 if (r_shadow_buffer_surfacepvs)
866                         Mem_Free(r_shadow_buffer_surfacepvs);
867                 if (r_shadow_buffer_surfacelist)
868                         Mem_Free(r_shadow_buffer_surfacelist);
869                 if (r_shadow_buffer_surfacesides)
870                         Mem_Free(r_shadow_buffer_surfacesides);
871                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
872                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
873                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
874                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
875         }
876         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
877         {
878                 if (r_shadow_buffer_shadowtrispvs)
879                         Mem_Free(r_shadow_buffer_shadowtrispvs);
880                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
881                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
882         }
883         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
884         {
885                 if (r_shadow_buffer_lighttrispvs)
886                         Mem_Free(r_shadow_buffer_lighttrispvs);
887                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
888                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
889         }
890 }
891
892 void R_Shadow_PrepareShadowMark(int numtris)
893 {
894         // make sure shadowmark is big enough for this volume
895         if (maxshadowmark < numtris)
896         {
897                 maxshadowmark = numtris;
898                 if (shadowmark)
899                         Mem_Free(shadowmark);
900                 if (shadowmarklist)
901                         Mem_Free(shadowmarklist);
902                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
903                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
904                 shadowmarkcount = 0;
905         }
906         shadowmarkcount++;
907         // if shadowmarkcount wrapped we clear the array and adjust accordingly
908         if (shadowmarkcount == 0)
909         {
910                 shadowmarkcount = 1;
911                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
912         }
913         numshadowmark = 0;
914 }
915
916 void R_Shadow_PrepareShadowSides(int numtris)
917 {
918     if (maxshadowsides < numtris)
919     {
920         maxshadowsides = numtris;
921         if (shadowsides)
922                         Mem_Free(shadowsides);
923                 if (shadowsideslist)
924                         Mem_Free(shadowsideslist);
925                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
926                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
927         }
928         numshadowsides = 0;
929 }
930
931 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)
932 {
933         int i, j;
934         int outtriangles = 0, outvertices = 0;
935         const int *element;
936         const float *vertex;
937         float ratio, direction[3], projectvector[3];
938
939         if (projectdirection)
940                 VectorScale(projectdirection, projectdistance, projectvector);
941         else
942                 VectorClear(projectvector);
943
944         // create the vertices
945         if (projectdirection)
946         {
947                 for (i = 0;i < numshadowmarktris;i++)
948                 {
949                         element = inelement3i + shadowmarktris[i] * 3;
950                         for (j = 0;j < 3;j++)
951                         {
952                                 if (vertexupdate[element[j]] != vertexupdatenum)
953                                 {
954                                         vertexupdate[element[j]] = vertexupdatenum;
955                                         vertexremap[element[j]] = outvertices;
956                                         vertex = invertex3f + element[j] * 3;
957                                         // project one copy of the vertex according to projectvector
958                                         VectorCopy(vertex, outvertex3f);
959                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
960                                         outvertex3f += 6;
961                                         outvertices += 2;
962                                 }
963                         }
964                 }
965         }
966         else
967         {
968                 for (i = 0;i < numshadowmarktris;i++)
969                 {
970                         element = inelement3i + shadowmarktris[i] * 3;
971                         for (j = 0;j < 3;j++)
972                         {
973                                 if (vertexupdate[element[j]] != vertexupdatenum)
974                                 {
975                                         vertexupdate[element[j]] = vertexupdatenum;
976                                         vertexremap[element[j]] = outvertices;
977                                         vertex = invertex3f + element[j] * 3;
978                                         // project one copy of the vertex to the sphere radius of the light
979                                         // (FIXME: would projecting it to the light box be better?)
980                                         VectorSubtract(vertex, projectorigin, direction);
981                                         ratio = projectdistance / VectorLength(direction);
982                                         VectorCopy(vertex, outvertex3f);
983                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
984                                         outvertex3f += 6;
985                                         outvertices += 2;
986                                 }
987                         }
988                 }
989         }
990
991         if (r_shadow_frontsidecasting.integer)
992         {
993                 for (i = 0;i < numshadowmarktris;i++)
994                 {
995                         int remappedelement[3];
996                         int markindex;
997                         const int *neighbortriangle;
998
999                         markindex = shadowmarktris[i] * 3;
1000                         element = inelement3i + markindex;
1001                         neighbortriangle = inneighbor3i + markindex;
1002                         // output the front and back triangles
1003                         outelement3i[0] = vertexremap[element[0]];
1004                         outelement3i[1] = vertexremap[element[1]];
1005                         outelement3i[2] = vertexremap[element[2]];
1006                         outelement3i[3] = vertexremap[element[2]] + 1;
1007                         outelement3i[4] = vertexremap[element[1]] + 1;
1008                         outelement3i[5] = vertexremap[element[0]] + 1;
1009
1010                         outelement3i += 6;
1011                         outtriangles += 2;
1012                         // output the sides (facing outward from this triangle)
1013                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1014                         {
1015                                 remappedelement[0] = vertexremap[element[0]];
1016                                 remappedelement[1] = vertexremap[element[1]];
1017                                 outelement3i[0] = remappedelement[1];
1018                                 outelement3i[1] = remappedelement[0];
1019                                 outelement3i[2] = remappedelement[0] + 1;
1020                                 outelement3i[3] = remappedelement[1];
1021                                 outelement3i[4] = remappedelement[0] + 1;
1022                                 outelement3i[5] = remappedelement[1] + 1;
1023
1024                                 outelement3i += 6;
1025                                 outtriangles += 2;
1026                         }
1027                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1028                         {
1029                                 remappedelement[1] = vertexremap[element[1]];
1030                                 remappedelement[2] = vertexremap[element[2]];
1031                                 outelement3i[0] = remappedelement[2];
1032                                 outelement3i[1] = remappedelement[1];
1033                                 outelement3i[2] = remappedelement[1] + 1;
1034                                 outelement3i[3] = remappedelement[2];
1035                                 outelement3i[4] = remappedelement[1] + 1;
1036                                 outelement3i[5] = remappedelement[2] + 1;
1037
1038                                 outelement3i += 6;
1039                                 outtriangles += 2;
1040                         }
1041                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1042                         {
1043                                 remappedelement[0] = vertexremap[element[0]];
1044                                 remappedelement[2] = vertexremap[element[2]];
1045                                 outelement3i[0] = remappedelement[0];
1046                                 outelement3i[1] = remappedelement[2];
1047                                 outelement3i[2] = remappedelement[2] + 1;
1048                                 outelement3i[3] = remappedelement[0];
1049                                 outelement3i[4] = remappedelement[2] + 1;
1050                                 outelement3i[5] = remappedelement[0] + 1;
1051
1052                                 outelement3i += 6;
1053                                 outtriangles += 2;
1054                         }
1055                 }
1056         }
1057         else
1058         {
1059                 for (i = 0;i < numshadowmarktris;i++)
1060                 {
1061                         int remappedelement[3];
1062                         int markindex;
1063                         const int *neighbortriangle;
1064
1065                         markindex = shadowmarktris[i] * 3;
1066                         element = inelement3i + markindex;
1067                         neighbortriangle = inneighbor3i + markindex;
1068                         // output the front and back triangles
1069                         outelement3i[0] = vertexremap[element[2]];
1070                         outelement3i[1] = vertexremap[element[1]];
1071                         outelement3i[2] = vertexremap[element[0]];
1072                         outelement3i[3] = vertexremap[element[0]] + 1;
1073                         outelement3i[4] = vertexremap[element[1]] + 1;
1074                         outelement3i[5] = vertexremap[element[2]] + 1;
1075
1076                         outelement3i += 6;
1077                         outtriangles += 2;
1078                         // output the sides (facing outward from this triangle)
1079                         if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1080                         {
1081                                 remappedelement[0] = vertexremap[element[0]];
1082                                 remappedelement[1] = vertexremap[element[1]];
1083                                 outelement3i[0] = remappedelement[0];
1084                                 outelement3i[1] = remappedelement[1];
1085                                 outelement3i[2] = remappedelement[1] + 1;
1086                                 outelement3i[3] = remappedelement[0];
1087                                 outelement3i[4] = remappedelement[1] + 1;
1088                                 outelement3i[5] = remappedelement[0] + 1;
1089
1090                                 outelement3i += 6;
1091                                 outtriangles += 2;
1092                         }
1093                         if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1094                         {
1095                                 remappedelement[1] = vertexremap[element[1]];
1096                                 remappedelement[2] = vertexremap[element[2]];
1097                                 outelement3i[0] = remappedelement[1];
1098                                 outelement3i[1] = remappedelement[2];
1099                                 outelement3i[2] = remappedelement[2] + 1;
1100                                 outelement3i[3] = remappedelement[1];
1101                                 outelement3i[4] = remappedelement[2] + 1;
1102                                 outelement3i[5] = remappedelement[1] + 1;
1103
1104                                 outelement3i += 6;
1105                                 outtriangles += 2;
1106                         }
1107                         if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1108                         {
1109                                 remappedelement[0] = vertexremap[element[0]];
1110                                 remappedelement[2] = vertexremap[element[2]];
1111                                 outelement3i[0] = remappedelement[2];
1112                                 outelement3i[1] = remappedelement[0];
1113                                 outelement3i[2] = remappedelement[0] + 1;
1114                                 outelement3i[3] = remappedelement[2];
1115                                 outelement3i[4] = remappedelement[0] + 1;
1116                                 outelement3i[5] = remappedelement[2] + 1;
1117
1118                                 outelement3i += 6;
1119                                 outtriangles += 2;
1120                         }
1121                 }
1122         }
1123         if (outnumvertices)
1124                 *outnumvertices = outvertices;
1125         return outtriangles;
1126 }
1127
1128 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)
1129 {
1130         int i, j, k;
1131         int outtriangles = 0, outvertices = 0;
1132         const int *element;
1133         const float *vertex;
1134         float ratio, direction[3], projectvector[3];
1135         qboolean side[4];
1136
1137         if (projectdirection)
1138                 VectorScale(projectdirection, projectdistance, projectvector);
1139         else
1140                 VectorClear(projectvector);
1141
1142         for (i = 0;i < numshadowmarktris;i++)
1143         {
1144                 int remappedelement[3];
1145                 int markindex;
1146                 const int *neighbortriangle;
1147
1148                 markindex = shadowmarktris[i] * 3;
1149                 neighbortriangle = inneighbor3i + markindex;
1150                 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1151                 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1152                 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1153                 if (side[0] + side[1] + side[2] == 0)
1154                         continue;
1155
1156                 side[3] = side[0];
1157                 element = inelement3i + markindex;
1158
1159                 // create the vertices
1160                 for (j = 0;j < 3;j++)
1161                 {
1162                         if (side[j] + side[j+1] == 0)
1163                                 continue;
1164                         k = element[j];
1165                         if (vertexupdate[k] != vertexupdatenum)
1166                         {
1167                                 vertexupdate[k] = vertexupdatenum;
1168                                 vertexremap[k] = outvertices;
1169                                 vertex = invertex3f + k * 3;
1170                                 VectorCopy(vertex, outvertex3f);
1171                                 if (projectdirection)
1172                                 {
1173                                         // project one copy of the vertex according to projectvector
1174                                         VectorAdd(vertex, projectvector, (outvertex3f + 3));
1175                                 }
1176                                 else
1177                                 {
1178                                         // project one copy of the vertex to the sphere radius of the light
1179                                         // (FIXME: would projecting it to the light box be better?)
1180                                         VectorSubtract(vertex, projectorigin, direction);
1181                                         ratio = projectdistance / VectorLength(direction);
1182                                         VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1183                                 }
1184                                 outvertex3f += 6;
1185                                 outvertices += 2;
1186                         }
1187                 }
1188
1189                 // output the sides (facing outward from this triangle)
1190                 if (!side[0])
1191                 {
1192                         remappedelement[0] = vertexremap[element[0]];
1193                         remappedelement[1] = vertexremap[element[1]];
1194                         outelement3i[0] = remappedelement[1];
1195                         outelement3i[1] = remappedelement[0];
1196                         outelement3i[2] = remappedelement[0] + 1;
1197                         outelement3i[3] = remappedelement[1];
1198                         outelement3i[4] = remappedelement[0] + 1;
1199                         outelement3i[5] = remappedelement[1] + 1;
1200
1201                         outelement3i += 6;
1202                         outtriangles += 2;
1203                 }
1204                 if (!side[1])
1205                 {
1206                         remappedelement[1] = vertexremap[element[1]];
1207                         remappedelement[2] = vertexremap[element[2]];
1208                         outelement3i[0] = remappedelement[2];
1209                         outelement3i[1] = remappedelement[1];
1210                         outelement3i[2] = remappedelement[1] + 1;
1211                         outelement3i[3] = remappedelement[2];
1212                         outelement3i[4] = remappedelement[1] + 1;
1213                         outelement3i[5] = remappedelement[2] + 1;
1214
1215                         outelement3i += 6;
1216                         outtriangles += 2;
1217                 }
1218                 if (!side[2])
1219                 {
1220                         remappedelement[0] = vertexremap[element[0]];
1221                         remappedelement[2] = vertexremap[element[2]];
1222                         outelement3i[0] = remappedelement[0];
1223                         outelement3i[1] = remappedelement[2];
1224                         outelement3i[2] = remappedelement[2] + 1;
1225                         outelement3i[3] = remappedelement[0];
1226                         outelement3i[4] = remappedelement[2] + 1;
1227                         outelement3i[5] = remappedelement[0] + 1;
1228
1229                         outelement3i += 6;
1230                         outtriangles += 2;
1231                 }
1232         }
1233         if (outnumvertices)
1234                 *outnumvertices = outvertices;
1235         return outtriangles;
1236 }
1237
1238 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)
1239 {
1240         int t, tend;
1241         const int *e;
1242         const float *v[3];
1243         float normal[3];
1244         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1245                 return;
1246         tend = firsttriangle + numtris;
1247         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1248         {
1249                 // surface box entirely inside light box, no box cull
1250                 if (projectdirection)
1251                 {
1252                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1253                         {
1254                                 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1255                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1256                                         shadowmarklist[numshadowmark++] = t;
1257                         }
1258                 }
1259                 else
1260                 {
1261                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1262                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1263                                         shadowmarklist[numshadowmark++] = t;
1264                 }
1265         }
1266         else
1267         {
1268                 // surface box not entirely inside light box, cull each triangle
1269                 if (projectdirection)
1270                 {
1271                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1272                         {
1273                                 v[0] = invertex3f + e[0] * 3;
1274                                 v[1] = invertex3f + e[1] * 3;
1275                                 v[2] = invertex3f + e[2] * 3;
1276                                 TriangleNormal(v[0], v[1], v[2], normal);
1277                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1278                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1279                                         shadowmarklist[numshadowmark++] = t;
1280                         }
1281                 }
1282                 else
1283                 {
1284                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1285                         {
1286                                 v[0] = invertex3f + e[0] * 3;
1287                                 v[1] = invertex3f + e[1] * 3;
1288                                 v[2] = invertex3f + e[2] * 3;
1289                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1290                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1291                                         shadowmarklist[numshadowmark++] = t;
1292                         }
1293                 }
1294         }
1295 }
1296
1297 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1298 {
1299 #if 1
1300         return false;
1301 #else
1302         if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1303                 return false;
1304         // check if the shadow volume intersects the near plane
1305         //
1306         // a ray between the eye and light origin may intersect the caster,
1307         // indicating that the shadow may touch the eye location, however we must
1308         // test the near plane (a polygon), not merely the eye location, so it is
1309         // easiest to enlarge the caster bounding shape slightly for this.
1310         // TODO
1311         return true;
1312 #endif
1313 }
1314
1315 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)
1316 {
1317         int i, tris, outverts;
1318         if (projectdistance < 0.1)
1319         {
1320                 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1321                 return;
1322         }
1323         if (!numverts || !nummarktris)
1324                 return;
1325         // make sure shadowelements is big enough for this volume
1326         if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1327                 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1328
1329         if (maxvertexupdate < numverts)
1330         {
1331                 maxvertexupdate = numverts;
1332                 if (vertexupdate)
1333                         Mem_Free(vertexupdate);
1334                 if (vertexremap)
1335                         Mem_Free(vertexremap);
1336                 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1337                 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1338                 vertexupdatenum = 0;
1339         }
1340         vertexupdatenum++;
1341         if (vertexupdatenum == 0)
1342         {
1343                 vertexupdatenum = 1;
1344                 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1345                 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1346         }
1347
1348         for (i = 0;i < nummarktris;i++)
1349                 shadowmark[marktris[i]] = shadowmarkcount;
1350
1351         if (r_shadow_compilingrtlight)
1352         {
1353                 // if we're compiling an rtlight, capture the mesh
1354                 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1355                 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1356                 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1358         }
1359         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1360         {
1361                 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1362                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1363                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1364         }
1365         else
1366         {
1367                 // decide which type of shadow to generate and set stencil mode
1368                 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1369                 // generate the sides or a solid volume, depending on type
1370                 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1371                         tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1372                 else
1373                         tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1374                 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1375                 r_refdef.stats.lights_shadowtriangles += tris;
1376                 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1377                 {
1378                         // increment stencil if frontface is infront of depthbuffer
1379                         GL_CullFace(r_refdef.view.cullface_front);
1380                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1381                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1382                         // decrement stencil if backface is infront of depthbuffer
1383                         GL_CullFace(r_refdef.view.cullface_back);
1384                         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1385                 }
1386                 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1387                 {
1388                         // decrement stencil if backface is behind depthbuffer
1389                         GL_CullFace(r_refdef.view.cullface_front);
1390                         R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1391                         R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1392                         // increment stencil if frontface is behind depthbuffer
1393                         GL_CullFace(r_refdef.view.cullface_back);
1394                         R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1395                 }
1396                 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1397                 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1398         }
1399 }
1400
1401 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1402 {
1403     // p1, p2, p3 are in the cubemap's local coordinate system
1404     // bias = border/(size - border)
1405         int mask = 0x3F;
1406
1407     float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1408           dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1409           dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1410         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1411         mask &= (3<<4)
1412                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1413                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1414                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1415     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1416         mask &= (3<<4)
1417             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1418             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))            
1419             | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1420
1421     dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1422     dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1423     dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1424     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1425         mask &= (3<<0)
1426             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1427             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))            
1428             | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1429     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1430         mask &= (3<<0)
1431             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1432             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1433             | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1434
1435     dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1436     dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1437     dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1438     if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1439         mask &= (3<<2)
1440             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1441             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1442             | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1443     if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1444         mask &= (3<<2)
1445             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1446             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1447             | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1448
1449         return mask;
1450 }
1451
1452 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1453 {
1454         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1455         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1456         int mask = 0x3F;
1457
1458         VectorSubtract(maxs, mins, radius);
1459     VectorScale(radius, 0.5f, radius);
1460     VectorAdd(mins, radius, center);
1461     Matrix4x4_Transform(worldtolight, center, lightcenter);
1462         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1463         VectorSubtract(lightcenter, lightradius, pmin);
1464         VectorAdd(lightcenter, lightradius, pmax);
1465
1466     dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1467     dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1468     if(ap1 > bias*an1 && ap2 > bias*an2)
1469         mask &= (3<<4)
1470             | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1471             | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1472     if(an1 > bias*ap1 && an2 > bias*ap2)
1473         mask &= (3<<4)
1474             | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1475             | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1476
1477     dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1478     dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1479     if(ap1 > bias*an1 && ap2 > bias*an2)
1480         mask &= (3<<0)
1481             | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1482             | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1483     if(an1 > bias*ap1 && an2 > bias*ap2)
1484         mask &= (3<<0)
1485             | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1486             | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1487
1488     dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1489     dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1490     if(ap1 > bias*an1 && ap2 > bias*an2)
1491         mask &= (3<<2)
1492             | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1493             | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1494     if(an1 > bias*ap1 && an2 > bias*ap2)
1495         mask &= (3<<2)
1496             | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1497             | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1498
1499     return mask;
1500 }
1501
1502 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1503
1504 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1505 {
1506     // p is in the cubemap's local coordinate system
1507     // bias = border/(size - border)
1508     float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1509     float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1510     float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1511     int mask = 0x3F;
1512     if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1513     if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1514     if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1515     if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1516     if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1517     if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1518     return mask;
1519 }
1520
1521 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1522 {
1523         int i;
1524         vec3_t p, n;
1525         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1526         float scale = (size - 2*border)/size, len;
1527         float bias = border / (float)(size - border), dp, dn, ap, an;
1528         // check if cone enclosing side would cross frustum plane 
1529         scale = 2 / (scale*scale + 2);
1530         for (i = 0;i < 5;i++)
1531         {
1532                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1533                         continue;
1534                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1535                 len = scale*VectorLength2(n);
1536                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1537                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1538                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1539         }
1540         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1541         {
1542         Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1543         len = scale*VectorLength(n);
1544                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1545                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1546                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1547         }
1548         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1549         // check if frustum corners/origin cross plane sides
1550 #if 1
1551     // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1552     Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1553     dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1554     masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1555     masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1556     dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1557     masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1558     masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1559     dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1560     masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1561     masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1562     for (i = 0;i < 4;i++)
1563     {
1564         Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1565         VectorSubtract(n, p, n);
1566         dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1567         if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1568         if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1569         dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1570         if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1571         if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1572         dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1573         if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1574         if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1575     }
1576 #else
1577     // finite version, assumes corners are a finite distance from origin dependent on far plane
1578         for (i = 0;i < 5;i++)
1579         {
1580                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1581                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1582                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1583                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1584                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1585                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1586                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1587                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1588                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1589                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1590         }
1591 #endif
1592         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1593 }
1594
1595 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)
1596 {
1597         int t, tend;
1598         const int *e;
1599         const float *v[3];
1600         float normal[3];
1601         vec3_t p[3];
1602         float bias;
1603         int mask, surfacemask = 0;
1604         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1605                 return 0;
1606         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1607         tend = firsttriangle + numtris;
1608         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1609         {
1610                 // surface box entirely inside light box, no box cull
1611                 if (projectdirection)
1612                 {
1613                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1614                         {
1615                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1616                                 TriangleNormal(v[0], v[1], v[2], normal);
1617                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1618                                 {
1619                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1620                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1621                                         surfacemask |= mask;
1622                                         if(totals)
1623                                         {
1624                                                 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;
1625                                                 shadowsides[numshadowsides] = mask;
1626                                                 shadowsideslist[numshadowsides++] = t;
1627                                         }
1628                                 }
1629                         }
1630                 }
1631                 else
1632                 {
1633                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1634                         {
1635                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1636                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1637                                 {
1638                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1639                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1640                                         surfacemask |= mask;
1641                                         if(totals)
1642                                         {
1643                                                 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;
1644                                                 shadowsides[numshadowsides] = mask;
1645                                                 shadowsideslist[numshadowsides++] = t;
1646                                         }
1647                                 }
1648                         }
1649                 }
1650         }
1651         else
1652         {
1653                 // surface box not entirely inside light box, cull each triangle
1654                 if (projectdirection)
1655                 {
1656                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1657                         {
1658                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1659                                 TriangleNormal(v[0], v[1], v[2], normal);
1660                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1661                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1662                                 {
1663                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1664                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1665                                         surfacemask |= mask;
1666                                         if(totals)
1667                                         {
1668                                                 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;
1669                                                 shadowsides[numshadowsides] = mask;
1670                                                 shadowsideslist[numshadowsides++] = t;
1671                                         }
1672                                 }
1673                         }
1674                 }
1675                 else
1676                 {
1677                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1678                         {
1679                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1680                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1681                                  && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1682                                 {
1683                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1684                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1685                                         surfacemask |= mask;
1686                                         if(totals)
1687                                         {
1688                                                 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;
1689                                                 shadowsides[numshadowsides] = mask;
1690                                                 shadowsideslist[numshadowsides++] = t;
1691                                         }
1692                                 }
1693                         }
1694                 }
1695         }
1696         return surfacemask;
1697 }
1698
1699 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)
1700 {
1701         int i, j, outtriangles = 0;
1702         int *outelement3i[6];
1703         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1704                 return;
1705         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1706         // make sure shadowelements is big enough for this mesh
1707         if (maxshadowtriangles < outtriangles)
1708                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1709
1710         // compute the offset and size of the separate index lists for each cubemap side
1711         outtriangles = 0;
1712         for (i = 0;i < 6;i++)
1713         {
1714                 outelement3i[i] = shadowelements + outtriangles * 3;
1715                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1716                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1717                 outtriangles += sidetotals[i];
1718         }
1719
1720         // gather up the (sparse) triangles into separate index lists for each cubemap side
1721         for (i = 0;i < numsidetris;i++)
1722         {
1723                 const int *element = elements + sidetris[i] * 3;
1724                 for (j = 0;j < 6;j++)
1725                 {
1726                         if (sides[i] & (1 << j))
1727                         {
1728                                 outelement3i[j][0] = element[0];
1729                                 outelement3i[j][1] = element[1];
1730                                 outelement3i[j][2] = element[2];
1731                                 outelement3i[j] += 3;
1732                         }
1733                 }
1734         }
1735                         
1736         Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1737 }
1738
1739 static void R_Shadow_MakeTextures_MakeCorona(void)
1740 {
1741         float dx, dy;
1742         int x, y, a;
1743         unsigned char pixels[32][32][4];
1744         for (y = 0;y < 32;y++)
1745         {
1746                 dy = (y - 15.5f) * (1.0f / 16.0f);
1747                 for (x = 0;x < 32;x++)
1748                 {
1749                         dx = (x - 15.5f) * (1.0f / 16.0f);
1750                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1751                         a = bound(0, a, 255);
1752                         pixels[y][x][0] = a;
1753                         pixels[y][x][1] = a;
1754                         pixels[y][x][2] = a;
1755                         pixels[y][x][3] = 255;
1756                 }
1757         }
1758         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1759 }
1760
1761 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1762 {
1763         float dist = sqrt(x*x+y*y+z*z);
1764         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1765         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1766         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1767 }
1768
1769 static void R_Shadow_MakeTextures(void)
1770 {
1771         int x, y, z;
1772         float intensity, dist;
1773         unsigned int *data;
1774         R_Shadow_FreeShadowMaps();
1775         R_FreeTexturePool(&r_shadow_texturepool);
1776         r_shadow_texturepool = R_AllocTexturePool();
1777         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1778         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1779         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1780         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1781         for (x = 0;x <= ATTENTABLESIZE;x++)
1782         {
1783                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1784                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1785                 r_shadow_attentable[x] = bound(0, intensity, 1);
1786         }
1787         // 1D gradient texture
1788         for (x = 0;x < ATTEN1DSIZE;x++)
1789                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1790         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1791         // 2D circle texture
1792         for (y = 0;y < ATTEN2DSIZE;y++)
1793                 for (x = 0;x < ATTEN2DSIZE;x++)
1794                         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);
1795         r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1796         // 3D sphere texture
1797         if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1798         {
1799                 for (z = 0;z < ATTEN3DSIZE;z++)
1800                         for (y = 0;y < ATTEN3DSIZE;y++)
1801                                 for (x = 0;x < ATTEN3DSIZE;x++)
1802                                         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));
1803                 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);
1804         }
1805         else
1806                 r_shadow_attenuation3dtexture = NULL;
1807         Mem_Free(data);
1808
1809         R_Shadow_MakeTextures_MakeCorona();
1810
1811         // Editor light sprites
1812         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1813         "................"
1814         ".3............3."
1815         "..5...2332...5.."
1816         "...7.3....3.7..."
1817         "....7......7...."
1818         "...3.7....7.3..."
1819         "..2...7..7...2.."
1820         "..3..........3.."
1821         "..3..........3.."
1822         "..2...7..7...2.."
1823         "...3.7....7.3..."
1824         "....7......7...."
1825         "...7.3....3.7..."
1826         "..5...2332...5.."
1827         ".3............3."
1828         "................"
1829         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1830         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1831         "................"
1832         "................"
1833         "......1111......"
1834         "....11233211...."
1835         "...1234554321..."
1836         "...1356776531..."
1837         "..124677776421.."
1838         "..135777777531.."
1839         "..135777777531.."
1840         "..124677776421.."
1841         "...1356776531..."
1842         "...1234554321..."
1843         "....11233211...."
1844         "......1111......"
1845         "................"
1846         "................"
1847         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1848         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1849         "................"
1850         "................"
1851         "......1111......"
1852         "....11233211...."
1853         "...1234554321..."
1854         "...1356226531..."
1855         "..12462..26421.."
1856         "..1352....2531.."
1857         "..1352....2531.."
1858         "..12462..26421.."
1859         "...1356226531..."
1860         "...1234554321..."
1861         "....11233211...."
1862         "......1111......"
1863         "................"
1864         "................"
1865         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1866         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1867         "................"
1868         "................"
1869         "......2772......"
1870         "....27755772...."
1871         "..277533335772.."
1872         "..753333333357.."
1873         "..777533335777.."
1874         "..735775577537.."
1875         "..733357753337.."
1876         "..733337733337.."
1877         "..753337733357.."
1878         "..277537735772.."
1879         "....27777772...."
1880         "......2772......"
1881         "................"
1882         "................"
1883         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1884         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1885         "................"
1886         "................"
1887         "......2772......"
1888         "....27722772...."
1889         "..2772....2772.."
1890         "..72........27.."
1891         "..7772....2777.."
1892         "..7.27722772.7.."
1893         "..7...2772...7.."
1894         "..7....77....7.."
1895         "..72...77...27.."
1896         "..2772.77.2772.."
1897         "....27777772...."
1898         "......2772......"
1899         "................"
1900         "................"
1901         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1902         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1903         "................"
1904         ".777752..257777."
1905         ".742........247."
1906         ".72..........27."
1907         ".7............7."
1908         ".5............5."
1909         ".2............2."
1910         "................"
1911         "................"
1912         ".2............2."
1913         ".5............5."
1914         ".7............7."
1915         ".72..........27."
1916         ".742........247."
1917         ".777752..257777."
1918         "................"
1919         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1920 }
1921
1922 void R_Shadow_ValidateCvars(void)
1923 {
1924         if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1925                 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1926         if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1927                 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1928         if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1929                 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1930 }
1931
1932 void R_Shadow_RenderMode_Begin(void)
1933 {
1934 #if 0
1935         GLint drawbuffer;
1936         GLint readbuffer;
1937 #endif
1938         R_Shadow_ValidateCvars();
1939
1940         if (!r_shadow_attenuation2dtexture
1941          || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1942          || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1943          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1944                 R_Shadow_MakeTextures();
1945
1946         CHECKGLERROR
1947         R_Mesh_ResetTextureState();
1948         GL_BlendFunc(GL_ONE, GL_ZERO);
1949         GL_DepthRange(0, 1);
1950         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1951         GL_DepthTest(true);
1952         GL_DepthMask(false);
1953         GL_Color(0, 0, 0, 1);
1954         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1955         
1956         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1957
1958         if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1959         {
1960                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1961                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1962         }
1963         else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1964         {
1965                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1966                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1967         }
1968         else
1969         {
1970                 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1971                 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1972         }
1973
1974         switch(vid.renderpath)
1975         {
1976         case RENDERPATH_GL20:
1977         case RENDERPATH_D3D9:
1978         case RENDERPATH_D3D10:
1979         case RENDERPATH_D3D11:
1980         case RENDERPATH_SOFT:
1981         case RENDERPATH_GLES2:
1982                 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1983                 break;
1984         case RENDERPATH_GL11:
1985         case RENDERPATH_GL13:
1986         case RENDERPATH_GLES1:
1987                 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1988                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1989                 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1990                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1991                 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1992                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1993                 else
1994                         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1995                 break;
1996         }
1997
1998         CHECKGLERROR
1999 #if 0
2000         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2001         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2002         r_shadow_drawbuffer = drawbuffer;
2003         r_shadow_readbuffer = readbuffer;
2004 #endif
2005         r_shadow_cullface_front = r_refdef.view.cullface_front;
2006         r_shadow_cullface_back = r_refdef.view.cullface_back;
2007 }
2008
2009 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2010 {
2011         rsurface.rtlight = rtlight;
2012 }
2013
2014 void R_Shadow_RenderMode_Reset(void)
2015 {
2016         R_Mesh_SetMainRenderTargets();
2017         R_SetViewport(&r_refdef.view.viewport);
2018         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2019         R_Mesh_ResetTextureState();
2020         GL_DepthRange(0, 1);
2021         GL_DepthTest(true);
2022         GL_DepthMask(false);
2023         GL_DepthFunc(GL_LEQUAL);
2024         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2025         r_refdef.view.cullface_front = r_shadow_cullface_front;
2026         r_refdef.view.cullface_back = r_shadow_cullface_back;
2027         GL_CullFace(r_refdef.view.cullface_back);
2028         GL_Color(1, 1, 1, 1);
2029         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2030         GL_BlendFunc(GL_ONE, GL_ZERO);
2031         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
2032         r_shadow_usingshadowmap2d = false;
2033         r_shadow_usingshadowmaportho = false;
2034         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2035 }
2036
2037 void R_Shadow_ClearStencil(void)
2038 {
2039         GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2040         r_refdef.stats.lights_clears++;
2041 }
2042
2043 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2044 {
2045         r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2046         if (r_shadow_rendermode == mode)
2047                 return;
2048         R_Shadow_RenderMode_Reset();
2049         GL_DepthFunc(GL_LESS);
2050         GL_ColorMask(0, 0, 0, 0);
2051         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2052         GL_CullFace(GL_NONE);
2053         R_SetupShader_DepthOrShadow(false);
2054         r_shadow_rendermode = mode;
2055         switch(mode)
2056         {
2057         default:
2058                 break;
2059         case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2060         case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2061                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2062                 break;
2063         case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2064         case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2065                 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2066                 break;
2067         }
2068 }
2069
2070 static void R_Shadow_MakeVSDCT(void)
2071 {
2072         // maps to a 2x3 texture rectangle with normalized coordinates
2073         // +-
2074         // XX
2075         // YY
2076         // ZZ
2077         // stores abs(dir.xy), offset.xy/2.5
2078         unsigned char data[4*6] =
2079         {
2080                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2081                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2082                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2083                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2084                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2085                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2086         };
2087         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2088 }
2089
2090 static void R_Shadow_MakeShadowMap(int side, int size)
2091 {
2092         switch (r_shadow_shadowmode)
2093         {
2094         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2095                 if (r_shadow_shadowmap2dtexture) return;
2096                 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2097                 r_shadow_shadowmap2dcolortexture = NULL;
2098                 switch(vid.renderpath)
2099                 {
2100 #ifdef SUPPORTD3D
2101                 case RENDERPATH_D3D9:
2102                         r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2103                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2104                         break;
2105 #endif
2106                 default:
2107                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2108                         break;
2109                 }
2110                 break;
2111         default:
2112                 return;
2113         }
2114
2115         // render depth into the fbo, do not render color at all
2116         // validate the fbo now
2117         if (qglDrawBuffer)
2118         {
2119                 int status;
2120                 qglDrawBuffer(GL_NONE);CHECKGLERROR
2121                 qglReadBuffer(GL_NONE);CHECKGLERROR
2122                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2123                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2124                 {
2125                         Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2126                         Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2127                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
2128                 }
2129         }
2130 }
2131
2132 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2133 {
2134         float nearclip, farclip, bias;
2135         r_viewport_t viewport;
2136         int flipped;
2137         GLuint fbo = 0;
2138         float clearcolor[4];
2139         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2140         farclip = 1.0f;
2141         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2142         r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2143         r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2144         r_shadow_shadowmapside = side;
2145         r_shadow_shadowmapsize = size;
2146
2147         r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2148         r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2149         R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2150         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2151
2152         // complex unrolled cube approach (more flexible)
2153         if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2154                 R_Shadow_MakeVSDCT();
2155         if (!r_shadow_shadowmap2dtexture)
2156                 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2157         if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2158         r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2159         r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2160         r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2161
2162         R_Mesh_ResetTextureState();
2163         R_Shadow_RenderMode_Reset();
2164         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2165         R_SetupShader_DepthOrShadow(true);
2166         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2167         GL_DepthMask(true);
2168         GL_DepthTest(true);
2169
2170 init_done:
2171         R_SetViewport(&viewport);
2172         flipped = (side & 1) ^ (side >> 2);
2173         r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2174         r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2175         switch(vid.renderpath)
2176         {
2177         case RENDERPATH_GL11:
2178         case RENDERPATH_GL13:
2179         case RENDERPATH_GL20:
2180         case RENDERPATH_SOFT:
2181         case RENDERPATH_GLES1:
2182         case RENDERPATH_GLES2:
2183                 GL_CullFace(r_refdef.view.cullface_back);
2184                 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2185                 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2186                 {
2187                         // get tightest scissor rectangle that encloses all viewports in the clear mask
2188                         int x1 = clear & 0x15 ? 0 : size;
2189                         int x2 = clear & 0x2A ? 2 * size : size;
2190                         int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2191                         int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2192                         GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2193                         GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2194                 }
2195                 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2196                 break;
2197         case RENDERPATH_D3D9:
2198         case RENDERPATH_D3D10:
2199         case RENDERPATH_D3D11:
2200                 Vector4Set(clearcolor, 1,1,1,1);
2201                 // completely different meaning than in OpenGL path
2202                 r_shadow_shadowmap_parameters[1] = 0;
2203                 r_shadow_shadowmap_parameters[3] = -bias;
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 (r_shadow_shadowmapsampler)
2210                 {
2211                         GL_ColorMask(0,0,0,0);
2212                         if (clear)
2213                                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2214                 }
2215                 else
2216                 {
2217                         GL_ColorMask(1,1,1,1);
2218                         if (clear)
2219                                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2220                 }
2221                 break;
2222         }
2223 }
2224
2225 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2226 {
2227         R_Mesh_ResetTextureState();
2228         R_Mesh_SetMainRenderTargets();
2229         if (transparent)
2230         {
2231                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2232                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2233                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2234                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2235         }
2236         R_Shadow_RenderMode_Reset();
2237         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2238         if (!transparent)
2239                 GL_DepthFunc(GL_EQUAL);
2240         // do global setup needed for the chosen lighting mode
2241         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2242                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2243         r_shadow_usingshadowmap2d = shadowmapping;
2244         r_shadow_rendermode = r_shadow_lightingrendermode;
2245         // only draw light where this geometry was already rendered AND the
2246         // stencil is 128 (values other than this mean shadow)
2247         if (stenciltest)
2248                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2249         else
2250                 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2251 }
2252
2253 static const unsigned short bboxelements[36] =
2254 {
2255         5, 1, 3, 5, 3, 7,
2256         6, 2, 0, 6, 0, 4,
2257         7, 3, 2, 7, 2, 6,
2258         4, 0, 1, 4, 1, 5,
2259         4, 5, 7, 4, 7, 6,
2260         1, 0, 2, 1, 2, 3,
2261 };
2262
2263 static const float bboxpoints[8][3] =
2264 {
2265         {-1,-1,-1},
2266         { 1,-1,-1},
2267         {-1, 1,-1},
2268         { 1, 1,-1},
2269         {-1,-1, 1},
2270         { 1,-1, 1},
2271         {-1, 1, 1},
2272         { 1, 1, 1},
2273 };
2274
2275 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2276 {
2277         int i;
2278         float vertex3f[8*3];
2279         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2280 // do global setup needed for the chosen lighting mode
2281         R_Shadow_RenderMode_Reset();
2282         r_shadow_rendermode = r_shadow_lightingrendermode;
2283         R_EntityMatrix(&identitymatrix);
2284         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2285         // only draw light where this geometry was already rendered AND the
2286         // stencil is 128 (values other than this mean shadow)
2287         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2288         if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2289                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2290         else
2291                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2292
2293         r_shadow_usingshadowmap2d = shadowmapping;
2294
2295         // render the lighting
2296         R_SetupShader_DeferredLight(rsurface.rtlight);
2297         for (i = 0;i < 8;i++)
2298                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2299         GL_ColorMask(1,1,1,1);
2300         GL_DepthMask(false);
2301         GL_DepthRange(0, 1);
2302         GL_PolygonOffset(0, 0);
2303         GL_DepthTest(true);
2304         GL_DepthFunc(GL_GREATER);
2305         GL_CullFace(r_refdef.view.cullface_back);
2306         R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2307         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2308 }
2309
2310 void R_Shadow_UpdateBounceGridTexture(void)
2311 {
2312 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2313         dlight_t *light;
2314         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2315         int bouncecount;
2316         int hitsupercontentsmask;
2317         int maxbounce;
2318         int numpixels;
2319         int resolution[3];
2320         int shootparticles;
2321         int shotparticles;
2322         int photoncount;
2323         int tex[3];
2324         trace_t cliptrace;
2325         //trace_t cliptrace2;
2326         //trace_t cliptrace3;
2327         unsigned char *pixel;
2328         unsigned char *pixels;
2329         float *highpixel;
2330         float *highpixels;
2331         unsigned int lightindex;
2332         unsigned int range;
2333         unsigned int range1;
2334         unsigned int range2;
2335         unsigned int seed = (unsigned int)(realtime * 1000.0f);
2336         vec3_t shotcolor;
2337         vec3_t baseshotcolor;
2338         vec3_t surfcolor;
2339         vec3_t clipend;
2340         vec3_t clipstart;
2341         vec3_t clipdiff;
2342         vec3_t ispacing;
2343         vec3_t maxs;
2344         vec3_t mins;
2345         vec3_t size;
2346         vec3_t spacing;
2347         vec3_t lightcolor;
2348         vec3_t steppos;
2349         vec3_t stepdelta;
2350         vec3_t cullmins, cullmaxs;
2351         vec_t radius;
2352         vec_t s;
2353         vec_t lightintensity;
2354         vec_t photonscaling;
2355         vec_t photonresidual;
2356         float m[16];
2357         float texlerp[2][3];
2358         float splatcolor[32];
2359         float pixelweight[8];
2360         float w;
2361         int c[4];
2362         int pixelindex[8];
2363         int corner;
2364         int pixelsperband;
2365         int pixelband;
2366         int pixelbands;
2367         int numsteps;
2368         int step;
2369         int x, y, z;
2370         rtlight_t *rtlight;
2371         r_shadow_bouncegrid_settings_t settings;
2372         qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2373         qboolean allowdirectionalshading = false;
2374         switch(vid.renderpath)
2375         {
2376         case RENDERPATH_GL20:
2377                 allowdirectionalshading = true;
2378                 if (!vid.support.ext_texture_3d)
2379                         return;
2380                 break;
2381         case RENDERPATH_GLES2:
2382                 // for performance reasons, do not use directional shading on GLES devices
2383                 if (!vid.support.ext_texture_3d)
2384                         return;
2385                 break;
2386                 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
2387         case RENDERPATH_GL11:
2388         case RENDERPATH_GL13:
2389         case RENDERPATH_GLES1:
2390         case RENDERPATH_SOFT:
2391         case RENDERPATH_D3D9:
2392         case RENDERPATH_D3D10:
2393         case RENDERPATH_D3D11:
2394                 return;
2395         }
2396
2397         r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2398
2399         // see if there are really any lights to render...
2400         if (enable && r_shadow_bouncegrid_static.integer)
2401         {
2402                 enable = false;
2403                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2404                 for (lightindex = 0;lightindex < range;lightindex++)
2405                 {
2406                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2407                         if (!light || !(light->flags & flag))
2408                                 continue;
2409                         rtlight = &light->rtlight;
2410                         // when static, we skip styled lights because they tend to change...
2411                         if (rtlight->style > 0)
2412                                 continue;
2413                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2414                         if (!VectorLength2(lightcolor))
2415                                 continue;
2416                         enable = true;
2417                         break;
2418                 }
2419         }
2420
2421         if (!enable)
2422         {
2423                 if (r_shadow_bouncegridtexture)
2424                 {
2425                         R_FreeTexture(r_shadow_bouncegridtexture);
2426                         r_shadow_bouncegridtexture = NULL;
2427                 }
2428                 if (r_shadow_bouncegridpixels)
2429                         Mem_Free(r_shadow_bouncegridpixels);
2430                 r_shadow_bouncegridpixels = NULL;
2431                 if (r_shadow_bouncegridhighpixels)
2432                         Mem_Free(r_shadow_bouncegridhighpixels);
2433                 r_shadow_bouncegridhighpixels = NULL;
2434                 r_shadow_bouncegridnumpixels = 0;
2435                 r_shadow_bouncegriddirectional = false;
2436                 return;
2437         }
2438
2439         // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2440         memset(&settings, 0, sizeof(settings));
2441         settings.staticmode                    = r_shadow_bouncegrid_static.integer != 0;
2442         settings.bounceanglediffuse            = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2443         settings.directionalshading            = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2444         settings.dlightparticlemultiplier      = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2445         settings.hitmodels                     = r_shadow_bouncegrid_hitmodels.integer != 0;
2446         settings.includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2447         settings.lightradiusscale              = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2448         settings.maxbounce                     = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2449         settings.particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
2450         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);
2451         settings.photons                       = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2452         settings.spacing[0]                    = r_shadow_bouncegrid_spacing.value;
2453         settings.spacing[1]                    = r_shadow_bouncegrid_spacing.value;
2454         settings.spacing[2]                    = r_shadow_bouncegrid_spacing.value;
2455         settings.stablerandom                  = r_shadow_bouncegrid_stablerandom.integer;
2456
2457         // bound the values for sanity
2458         settings.photons = bound(1, settings.photons, 1048576);
2459         settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2460         settings.maxbounce = bound(0, settings.maxbounce, 16);
2461         settings.spacing[0] = bound(1, settings.spacing[0], 512);
2462         settings.spacing[1] = bound(1, settings.spacing[1], 512);
2463         settings.spacing[2] = bound(1, settings.spacing[2], 512);
2464
2465         // get the spacing values
2466         spacing[0] = settings.spacing[0];
2467         spacing[1] = settings.spacing[1];
2468         spacing[2] = settings.spacing[2];
2469         ispacing[0] = 1.0f / spacing[0];
2470         ispacing[1] = 1.0f / spacing[1];
2471         ispacing[2] = 1.0f / spacing[2];
2472
2473         // calculate texture size enclosing entire world bounds at the spacing
2474         VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2475         VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2476         VectorSubtract(maxs, mins, size);
2477         // now we can calculate the resolution we want
2478         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2479         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2480         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2481         // figure out the exact texture size (honoring power of 2 if required)
2482         c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2483         c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2484         c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2485         if (vid.support.arb_texture_non_power_of_two)
2486         {
2487                 resolution[0] = c[0];
2488                 resolution[1] = c[1];
2489                 resolution[2] = c[2];
2490         }
2491         else
2492         {
2493                 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2494                 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2495                 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2496         }
2497         size[0] = spacing[0] * resolution[0];
2498         size[1] = spacing[1] * resolution[1];
2499         size[2] = spacing[2] * resolution[2];
2500
2501         // if dynamic we may or may not want to use the world bounds
2502         // if the dynamic size is smaller than the world bounds, use it instead
2503         if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2504         {
2505                 // we know the resolution we want
2506                 c[0] = r_shadow_bouncegrid_x.integer;
2507                 c[1] = r_shadow_bouncegrid_y.integer;
2508                 c[2] = r_shadow_bouncegrid_z.integer;
2509                 // now we can calculate the texture size (power of 2 if required)
2510                 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2511                 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2512                 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2513                 if (vid.support.arb_texture_non_power_of_two)
2514                 {
2515                         resolution[0] = c[0];
2516                         resolution[1] = c[1];
2517                         resolution[2] = c[2];
2518                 }
2519                 else
2520                 {
2521                         for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2522                         for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2523                         for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2524                 }
2525                 size[0] = spacing[0] * resolution[0];
2526                 size[1] = spacing[1] * resolution[1];
2527                 size[2] = spacing[2] * resolution[2];
2528                 // center the rendering on the view
2529                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2530                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2531                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2532         }
2533
2534         // recalculate the maxs in case the resolution was not satisfactory
2535         VectorAdd(mins, size, maxs);
2536
2537         // if all the settings seem identical to the previous update, return
2538         if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2539                 return;
2540
2541         // store the new settings
2542         r_shadow_bouncegridsettings = settings;
2543
2544         pixelbands = settings.directionalshading ? 8 : 1;
2545         pixelsperband = resolution[0]*resolution[1]*resolution[2];
2546         numpixels = pixelsperband*pixelbands;
2547
2548         // we're going to update the bouncegrid, update the matrix...
2549         memset(m, 0, sizeof(m));
2550         m[0] = 1.0f / size[0];
2551         m[3] = -mins[0] * m[0];
2552         m[5] = 1.0f / size[1];
2553         m[7] = -mins[1] * m[5];
2554         m[10] = 1.0f / size[2];
2555         m[11] = -mins[2] * m[10];
2556         m[15] = 1.0f;
2557         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2558         // reallocate pixels for this update if needed...
2559         if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2560         {
2561                 if (r_shadow_bouncegridtexture)
2562                 {
2563                         R_FreeTexture(r_shadow_bouncegridtexture);
2564                         r_shadow_bouncegridtexture = NULL;
2565                 }
2566                 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2567                 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2568         }
2569         r_shadow_bouncegridnumpixels = numpixels;
2570         pixels = r_shadow_bouncegridpixels;
2571         highpixels = r_shadow_bouncegridhighpixels;
2572         x = pixelsperband*4;
2573         for (pixelband = 0;pixelband < pixelbands;pixelband++)
2574         {
2575                 if (pixelband == 1)
2576                         memset(pixels + pixelband * x, 128, x);
2577                 else
2578                         memset(pixels + pixelband * x, 0, x);
2579         }
2580         memset(highpixels, 0, numpixels * sizeof(float[4]));
2581         // figure out what we want to interact with
2582         if (settings.hitmodels)
2583                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2584         else
2585                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2586         maxbounce = settings.maxbounce;
2587         // clear variables that produce warnings otherwise
2588         memset(splatcolor, 0, sizeof(splatcolor));
2589         // iterate world rtlights
2590         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2591         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2592         range2 = range + range1;
2593         photoncount = 0;
2594         for (lightindex = 0;lightindex < range2;lightindex++)
2595         {
2596                 if (lightindex < range)
2597                 {
2598                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2599                         if (!light)
2600                                 continue;
2601                         rtlight = &light->rtlight;
2602                         VectorClear(rtlight->photoncolor);
2603                         rtlight->photons = 0;
2604                         if (!(light->flags & flag))
2605                                 continue;
2606                         if (settings.staticmode)
2607                         {
2608                                 // when static, we skip styled lights because they tend to change...
2609                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2610                                         continue;
2611                         }
2612                 }
2613                 else
2614                 {
2615                         rtlight = r_refdef.scene.lights[lightindex - range];
2616                         VectorClear(rtlight->photoncolor);
2617                         rtlight->photons = 0;
2618                 }
2619                 // draw only visible lights (major speedup)
2620                 radius = rtlight->radius * settings.lightradiusscale;
2621                 cullmins[0] = rtlight->shadoworigin[0] - radius;
2622                 cullmins[1] = rtlight->shadoworigin[1] - radius;
2623                 cullmins[2] = rtlight->shadoworigin[2] - radius;
2624                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2625                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2626                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2627                 if (R_CullBox(cullmins, cullmaxs))
2628                         continue;
2629                 if (r_refdef.scene.worldmodel
2630                  && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2631                  && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2632                         continue;
2633                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2634                 if (w * VectorLength2(rtlight->color) == 0.0f)
2635                         continue;
2636                 w *= (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2637                 VectorScale(rtlight->color, w, rtlight->photoncolor);
2638                 //if (!VectorLength2(rtlight->photoncolor))
2639                 //      continue;
2640                 // shoot particles from this light
2641                 // use a calculation for the number of particles that will not
2642                 // vary with lightstyle, otherwise we get randomized particle
2643                 // distribution, the seeded random is only consistent for a
2644                 // consistent number of particles on this light...
2645                 s = rtlight->radius;
2646                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2647                 if (lightindex >= range)
2648                         lightintensity *= settings.dlightparticlemultiplier;
2649                 rtlight->photons = max(0.0f, lightintensity * s * s);
2650                 photoncount += rtlight->photons;
2651         }
2652         photonscaling = (float)settings.photons / max(1, photoncount);
2653         photonresidual = 0.0f;
2654         for (lightindex = 0;lightindex < range2;lightindex++)
2655         {
2656                 if (lightindex < range)
2657                 {
2658                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2659                         if (!light)
2660                                 continue;
2661                         rtlight = &light->rtlight;
2662                 }
2663                 else
2664                         rtlight = r_refdef.scene.lights[lightindex - range];
2665                 // skip a light with no photons
2666                 if (rtlight->photons == 0.0f)
2667                         continue;
2668                 // skip a light with no photon color)
2669                 if (VectorLength2(rtlight->photoncolor) == 0.0f)
2670                         continue;
2671                 photonresidual += rtlight->photons * photonscaling;
2672                 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2673                 if (!shootparticles)
2674                         continue;
2675                 photonresidual -= shootparticles;
2676                 radius = rtlight->radius * settings.lightradiusscale;
2677                 s = settings.particleintensity / shootparticles;
2678                 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2679                 r_refdef.stats.bouncegrid_lights++;
2680                 r_refdef.stats.bouncegrid_particles += shootparticles;
2681                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2682                 {
2683                         if (settings.stablerandom > 0)
2684                                 seed = lightindex * 11937 + shotparticles;
2685                         VectorCopy(baseshotcolor, shotcolor);
2686                         VectorCopy(rtlight->shadoworigin, clipstart);
2687                         if (settings.stablerandom < 0)
2688                                 VectorRandom(clipend);
2689                         else
2690                                 VectorCheeseRandom(clipend);
2691                         VectorMA(clipstart, radius, clipend, clipend);
2692                         for (bouncecount = 0;;bouncecount++)
2693                         {
2694                                 r_refdef.stats.bouncegrid_traces++;
2695                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2696                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2697                                 //if (settings.staticmode)
2698                                 //      Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
2699                                 //else
2700                                         cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
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 = 4096;
3171         static int newelements[4096*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;
3325         diffusescale = rsurface.rtlight->diffusescale;
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 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 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 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 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 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 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 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 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_prepassgeometrydepthtexture)
4383                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4384         r_shadow_prepassgeometrydepthtexture = NULL;
4385
4386         if (r_shadow_prepassgeometrydepthcolortexture)
4387                 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4388         r_shadow_prepassgeometrydepthcolortexture = NULL;
4389
4390         if (r_shadow_prepassgeometrynormalmaptexture)
4391                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4392         r_shadow_prepassgeometrynormalmaptexture = NULL;
4393
4394         if (r_shadow_prepasslightingdiffusetexture)
4395                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4396         r_shadow_prepasslightingdiffusetexture = NULL;
4397
4398         if (r_shadow_prepasslightingspeculartexture)
4399                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4400         r_shadow_prepasslightingspeculartexture = NULL;
4401 }
4402
4403 void R_Shadow_DrawPrepass(void)
4404 {
4405         int i;
4406         int flag;
4407         int lnum;
4408         size_t lightindex;
4409         dlight_t *light;
4410         size_t range;
4411         entity_render_t *ent;
4412         float clearcolor[4];
4413
4414         R_Mesh_ResetTextureState();
4415         GL_DepthMask(true);
4416         GL_ColorMask(1,1,1,1);
4417         GL_BlendFunc(GL_ONE, GL_ZERO);
4418         GL_Color(1,1,1,1);
4419         GL_DepthTest(true);
4420         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4421         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4422         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4423         if (r_timereport_active)
4424                 R_TimeReport("prepasscleargeom");
4425
4426         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4427                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4428         if (r_timereport_active)
4429                 R_TimeReport("prepassworld");
4430
4431         for (i = 0;i < r_refdef.scene.numentities;i++)
4432         {
4433                 if (!r_refdef.viewcache.entityvisible[i])
4434                         continue;
4435                 ent = r_refdef.scene.entities[i];
4436                 if (ent->model && ent->model->DrawPrepass != NULL)
4437                         ent->model->DrawPrepass(ent);
4438         }
4439
4440         if (r_timereport_active)
4441                 R_TimeReport("prepassmodels");
4442
4443         GL_DepthMask(false);
4444         GL_ColorMask(1,1,1,1);
4445         GL_Color(1,1,1,1);
4446         GL_DepthTest(true);
4447         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4448         Vector4Set(clearcolor, 0, 0, 0, 0);
4449         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4450         if (r_timereport_active)
4451                 R_TimeReport("prepassclearlit");
4452
4453         R_Shadow_RenderMode_Begin();
4454
4455         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4456         if (r_shadow_debuglight.integer >= 0)
4457         {
4458                 lightindex = r_shadow_debuglight.integer;
4459                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4460                 if (light && (light->flags & flag) && light->rtlight.draw)
4461                         R_Shadow_DrawLight(&light->rtlight);
4462         }
4463         else
4464         {
4465                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4466                 for (lightindex = 0;lightindex < range;lightindex++)
4467                 {
4468                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4469                         if (light && (light->flags & flag) && light->rtlight.draw)
4470                                 R_Shadow_DrawLight(&light->rtlight);
4471                 }
4472         }
4473         if (r_refdef.scene.rtdlight)
4474                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4475                         if (r_refdef.scene.lights[lnum]->draw)
4476                                 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4477
4478         R_Mesh_SetMainRenderTargets();
4479
4480         R_Shadow_RenderMode_End();
4481
4482         if (r_timereport_active)
4483                 R_TimeReport("prepasslights");
4484 }
4485
4486 void R_Shadow_DrawLightSprites(void);
4487 void R_Shadow_PrepareLights(void)
4488 {
4489         int flag;
4490         int lnum;
4491         size_t lightindex;
4492         dlight_t *light;
4493         size_t range;
4494         float f;
4495         GLenum status;
4496
4497         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4498                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4499                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
4500                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4501                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4502                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4503                 R_Shadow_FreeShadowMaps();
4504
4505         r_shadow_usingshadowmaportho = false;
4506
4507         switch (vid.renderpath)
4508         {
4509         case RENDERPATH_GL20:
4510         case RENDERPATH_D3D9:
4511         case RENDERPATH_D3D10:
4512         case RENDERPATH_D3D11:
4513         case RENDERPATH_SOFT:
4514         case RENDERPATH_GLES2:
4515                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4516                 {
4517                         r_shadow_usingdeferredprepass = false;
4518                         if (r_shadow_prepass_width)
4519                                 R_Shadow_FreeDeferred();
4520                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4521                         break;
4522                 }
4523
4524                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4525                 {
4526                         R_Shadow_FreeDeferred();
4527
4528                         r_shadow_usingdeferredprepass = true;
4529                         r_shadow_prepass_width = vid.width;
4530                         r_shadow_prepass_height = vid.height;
4531                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4532                         switch (vid.renderpath)
4533                         {
4534                         case RENDERPATH_D3D9:
4535                                 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4536                                 break;
4537                         default:
4538                                 break;
4539                         }
4540                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4541                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4542                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4543
4544                         // set up the geometry pass fbo (depth + normalmap)
4545                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4546                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4547                         // render depth into one texture and normalmap into the other
4548                         if (qglDrawBuffersARB)
4549                         {
4550                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4551                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4552                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4553                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4554                                 {
4555                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4556                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4557                                         r_shadow_usingdeferredprepass = false;
4558                                 }
4559                         }
4560
4561                         // set up the lighting pass fbo (diffuse + specular)
4562                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4563                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4564                         // render diffuse into one texture and specular into another,
4565                         // with depth and normalmap bound as textures,
4566                         // with depth bound as attachment as well
4567                         if (qglDrawBuffersARB)
4568                         {
4569                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4570                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4571                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4572                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4573                                 {
4574                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4575                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4576                                         r_shadow_usingdeferredprepass = false;
4577                                 }
4578                         }
4579
4580                         // set up the lighting pass fbo (diffuse)
4581                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4582                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4583                         // render diffuse into one texture,
4584                         // with depth and normalmap bound as textures,
4585                         // with depth bound as attachment as well
4586                         if (qglDrawBuffersARB)
4587                         {
4588                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4589                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4590                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4591                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4592                                 {
4593                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4594                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4595                                         r_shadow_usingdeferredprepass = false;
4596                                 }
4597                         }
4598                 }
4599                 break;
4600         case RENDERPATH_GL11:
4601         case RENDERPATH_GL13:
4602         case RENDERPATH_GLES1:
4603                 r_shadow_usingdeferredprepass = false;
4604                 break;
4605         }
4606
4607         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);
4608
4609         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4610         if (r_shadow_bouncegrid.integer != 2)
4611         {
4612                 if (r_shadow_debuglight.integer >= 0)
4613                 {
4614                         lightindex = r_shadow_debuglight.integer;
4615                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4616                         if (light)
4617                                 R_Shadow_PrepareLight(&light->rtlight);
4618                 }
4619                 else
4620                 {
4621                         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4622                         for (lightindex = 0;lightindex < range;lightindex++)
4623                         {
4624                                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4625                                 if (light && (light->flags & flag))
4626                                         R_Shadow_PrepareLight(&light->rtlight);
4627                         }
4628                 }
4629         }
4630         if (r_refdef.scene.rtdlight)
4631         {
4632                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4633                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4634         }
4635         else if(gl_flashblend.integer)
4636         {
4637                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4638                 {
4639                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4640                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4641                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4642                 }
4643         }
4644
4645         if (r_editlights.integer)
4646                 R_Shadow_DrawLightSprites();
4647 }
4648
4649 void R_Shadow_DrawLights(void)
4650 {
4651         int flag;
4652         int lnum;
4653         size_t lightindex;
4654         dlight_t *light;
4655         size_t range;
4656
4657         R_Shadow_RenderMode_Begin();
4658
4659         if (r_shadow_bouncegrid.integer != 2)
4660         {
4661                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4662                 if (r_shadow_debuglight.integer >= 0)
4663                 {
4664                         lightindex = r_shadow_debuglight.integer;
4665                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4666                         if (light)
4667                                 R_Shadow_DrawLight(&light->rtlight);
4668                 }
4669                 else
4670                 {
4671                         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4672                         for (lightindex = 0;lightindex < range;lightindex++)
4673                         {
4674                                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4675                                 if (light && (light->flags & flag))
4676                                         R_Shadow_DrawLight(&light->rtlight);
4677                         }
4678                 }
4679         }
4680         if (r_refdef.scene.rtdlight)
4681                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4682                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4683
4684         R_Shadow_RenderMode_End();
4685 }
4686
4687 extern const float r_screenvertex3f[12];
4688 extern void R_SetupView(qboolean allowwaterclippingplane);
4689 extern void R_ResetViewRendering3D(void);
4690 extern void R_ResetViewRendering2D(void);
4691 extern cvar_t r_shadows;
4692 extern cvar_t r_shadows_darken;
4693 extern cvar_t r_shadows_drawafterrtlighting;
4694 extern cvar_t r_shadows_castfrombmodels;
4695 extern cvar_t r_shadows_throwdistance;
4696 extern cvar_t r_shadows_throwdirection;
4697 extern cvar_t r_shadows_focus;
4698 extern cvar_t r_shadows_shadowmapscale;
4699
4700 void R_Shadow_PrepareModelShadows(void)
4701 {
4702         int i;
4703         float scale, size, radius, dot1, dot2;
4704         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4705         entity_render_t *ent;
4706
4707         if (!r_refdef.scene.numentities)
4708                 return;
4709
4710         switch (r_shadow_shadowmode)
4711         {
4712         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4713                 if (r_shadows.integer >= 2) 
4714                         break;
4715                 // fall through
4716         case R_SHADOW_SHADOWMODE_STENCIL:
4717                 for (i = 0;i < r_refdef.scene.numentities;i++)
4718                 {
4719                         ent = r_refdef.scene.entities[i];
4720                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4721                                 R_AnimCache_GetEntity(ent, false, false);
4722                 }
4723                 return;
4724         default:
4725                 return;
4726         }
4727
4728         size = 2*r_shadow_shadowmapmaxsize;
4729         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4730         radius = 0.5f * size / scale;
4731
4732         Math_atov(r_shadows_throwdirection.string, shadowdir);
4733         VectorNormalize(shadowdir);
4734         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4735         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4736         if (fabs(dot1) <= fabs(dot2))
4737                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4738         else
4739                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4740         VectorNormalize(shadowforward);
4741         CrossProduct(shadowdir, shadowforward, shadowright);
4742         Math_atov(r_shadows_focus.string, shadowfocus);
4743         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4744         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4745         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4746         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4747         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4748                 dot1 = 1;
4749         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4750
4751         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4752         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4753         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4754         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4755         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4756         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4757
4758         for (i = 0;i < r_refdef.scene.numentities;i++)
4759         {
4760                 ent = r_refdef.scene.entities[i];
4761                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4762                         continue;
4763                 // cast shadows from anything of the map (submodels are optional)
4764                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4765                         R_AnimCache_GetEntity(ent, false, false);
4766         }
4767 }
4768
4769 void R_DrawModelShadowMaps(void)
4770 {
4771         int i;
4772         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4773         entity_render_t *ent;
4774         vec3_t relativelightorigin;
4775         vec3_t relativelightdirection, relativeforward, relativeright;
4776         vec3_t relativeshadowmins, relativeshadowmaxs;
4777         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4778         float m[12];
4779         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4780         r_viewport_t viewport;
4781         GLuint fbo = 0;
4782         float clearcolor[4];
4783
4784         if (!r_refdef.scene.numentities)
4785                 return;
4786
4787         switch (r_shadow_shadowmode)
4788         {
4789         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4790                 break;
4791         default:
4792                 return;
4793         }
4794
4795         R_ResetViewRendering3D();
4796         R_Shadow_RenderMode_Begin();
4797         R_Shadow_RenderMode_ActiveLight(NULL);
4798
4799         switch (r_shadow_shadowmode)
4800         {
4801         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4802                 if (!r_shadow_shadowmap2dtexture)
4803                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4804                 fbo = r_shadow_fbo2d;
4805                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4806                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4807                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4808                 break;
4809         default:
4810                 break;
4811         }
4812
4813         size = 2*r_shadow_shadowmapmaxsize;
4814         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4815         radius = 0.5f / scale;
4816         nearclip = -r_shadows_throwdistance.value;
4817         farclip = r_shadows_throwdistance.value;
4818         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4819
4820         r_shadow_shadowmap_parameters[0] = size;
4821         r_shadow_shadowmap_parameters[1] = size;
4822         r_shadow_shadowmap_parameters[2] = 1.0;
4823         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4824
4825         Math_atov(r_shadows_throwdirection.string, shadowdir);
4826         VectorNormalize(shadowdir);
4827         Math_atov(r_shadows_focus.string, shadowfocus);
4828         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4829         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4830         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4831         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4832         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4833         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4834         if (fabs(dot1) <= fabs(dot2)) 
4835                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4836         else
4837                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4838         VectorNormalize(shadowforward);
4839         VectorM(scale, shadowforward, &m[0]);
4840         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4841                 dot1 = 1;
4842         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4843         CrossProduct(shadowdir, shadowforward, shadowright);
4844         VectorM(scale, shadowright, &m[4]);
4845         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4846         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4847         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4848         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4849         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4850         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4851
4852         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4853
4854         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4855         R_SetupShader_DepthOrShadow(true);
4856         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4857         GL_DepthMask(true);
4858         GL_DepthTest(true);
4859         R_SetViewport(&viewport);
4860         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4861         Vector4Set(clearcolor, 1,1,1,1);
4862         // in D3D9 we have to render to a color texture shadowmap
4863         // in GL we render directly to a depth texture only
4864         if (r_shadow_shadowmap2dtexture)
4865                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4866         else
4867                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4868         // render into a slightly restricted region so that the borders of the
4869         // shadowmap area fade away, rather than streaking across everything
4870         // outside the usable area
4871         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4872
4873 #if 0
4874         // debugging
4875         R_Mesh_SetMainRenderTargets();
4876         R_SetupShader_ShowDepth(true);
4877         GL_ColorMask(1,1,1,1);
4878         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4879 #endif
4880
4881         for (i = 0;i < r_refdef.scene.numentities;i++)
4882         {
4883                 ent = r_refdef.scene.entities[i];
4884
4885                 // cast shadows from anything of the map (submodels are optional)
4886                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4887                 {
4888                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4889                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4890                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4891                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4892                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4893                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4894                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4895                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4896                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4897                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4898                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4899                         RSurf_ActiveModelEntity(ent, false, false, false);
4900                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4901                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4902                 }
4903         }
4904
4905 #if 0
4906         if (r_test.integer)
4907         {
4908                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4909                 CHECKGLERROR
4910                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4911                 CHECKGLERROR
4912                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4913                 Cvar_SetValueQuick(&r_test, 0);
4914                 Z_Free(rawpixels);
4915         }
4916 #endif
4917
4918         R_Shadow_RenderMode_End();
4919
4920         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4921         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4922         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4923         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4924         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4925         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4926
4927         switch (vid.renderpath)
4928         {
4929         case RENDERPATH_GL11:
4930         case RENDERPATH_GL13:
4931         case RENDERPATH_GL20:
4932         case RENDERPATH_SOFT:
4933         case RENDERPATH_GLES1:
4934         case RENDERPATH_GLES2:
4935                 break;
4936         case RENDERPATH_D3D9:
4937         case RENDERPATH_D3D10:
4938         case RENDERPATH_D3D11:
4939 #ifdef OPENGL_ORIENTATION
4940                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4941                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
4942                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
4943                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
4944 #else
4945                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4946                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
4947                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
4948                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
4949 #endif
4950                 break;
4951         }
4952
4953         r_shadow_usingshadowmaportho = true;
4954         switch (r_shadow_shadowmode)
4955         {
4956         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4957                 r_shadow_usingshadowmap2d = true;
4958                 break;
4959         default:
4960                 break;
4961         }
4962 }
4963
4964 void R_DrawModelShadows(void)
4965 {
4966         int i;
4967         float relativethrowdistance;
4968         entity_render_t *ent;
4969         vec3_t relativelightorigin;
4970         vec3_t relativelightdirection;
4971         vec3_t relativeshadowmins, relativeshadowmaxs;
4972         vec3_t tmp, shadowdir;
4973
4974         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4975                 return;
4976
4977         R_ResetViewRendering3D();
4978         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4979         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4980         R_Shadow_RenderMode_Begin();
4981         R_Shadow_RenderMode_ActiveLight(NULL);
4982         r_shadow_lightscissor[0] = r_refdef.view.x;
4983         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4984         r_shadow_lightscissor[2] = r_refdef.view.width;
4985         r_shadow_lightscissor[3] = r_refdef.view.height;
4986         R_Shadow_RenderMode_StencilShadowVolumes(false);
4987
4988         // get shadow dir
4989         if (r_shadows.integer == 2)
4990         {
4991                 Math_atov(r_shadows_throwdirection.string, shadowdir);
4992                 VectorNormalize(shadowdir);
4993         }
4994
4995         R_Shadow_ClearStencil();
4996
4997         for (i = 0;i < r_refdef.scene.numentities;i++)
4998         {
4999                 ent = r_refdef.scene.entities[i];
5000
5001                 // cast shadows from anything of the map (submodels are optional)
5002                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5003                 {
5004                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5005                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5006                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5007                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5008                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5009                         else
5010                         {
5011                                 if(ent->entitynumber != 0)
5012                                 {
5013                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5014                                         {
5015                                                 // FIXME handle this
5016                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5017                                         }
5018                                         else
5019                                         {
5020                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5021                                                 int entnum, entnum2, recursion;
5022                                                 entnum = entnum2 = ent->entitynumber;
5023                                                 for(recursion = 32; recursion > 0; --recursion)
5024                                                 {
5025                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
5026                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5027                                                                 entnum = entnum2;
5028                                                         else
5029                                                                 break;
5030                                                 }
5031                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5032                                                 {
5033                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5034                                                         // transform into modelspace of OUR entity
5035                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5036                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5037                                                 }
5038                                                 else
5039                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5040                                         }
5041                                 }
5042                                 else
5043                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5044                         }
5045
5046                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5047                         RSurf_ActiveModelEntity(ent, false, false, false);
5048                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5049                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5050                 }
5051         }
5052
5053         // not really the right mode, but this will disable any silly stencil features
5054         R_Shadow_RenderMode_End();
5055
5056         // set up ortho view for rendering this pass
5057         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5058         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5059         //GL_ScissorTest(true);
5060         //R_EntityMatrix(&identitymatrix);
5061         //R_Mesh_ResetTextureState();
5062         R_ResetViewRendering2D();
5063
5064         // set up a darkening blend on shadowed areas
5065         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5066         //GL_DepthRange(0, 1);
5067         //GL_DepthTest(false);
5068         //GL_DepthMask(false);
5069         //GL_PolygonOffset(0, 0);CHECKGLERROR
5070         GL_Color(0, 0, 0, r_shadows_darken.value);
5071         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5072         //GL_DepthFunc(GL_ALWAYS);
5073         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5074
5075         // apply the blend to the shadowed areas
5076         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5077         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, true);
5078         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5079
5080         // restore the viewport
5081         R_SetViewport(&r_refdef.view.viewport);
5082
5083         // restore other state to normal
5084         //R_Shadow_RenderMode_End();
5085 }
5086
5087 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5088 {
5089         float zdist;
5090         vec3_t centerorigin;
5091         float vertex3f[12];
5092         // if it's too close, skip it
5093         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5094                 return;
5095         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5096         if (zdist < 32)
5097                 return;
5098         if (usequery && r_numqueries + 2 <= r_maxqueries)
5099         {
5100                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5101                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5102                 // 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
5103                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5104
5105                 switch(vid.renderpath)
5106                 {
5107                 case RENDERPATH_GL11:
5108                 case RENDERPATH_GL13:
5109                 case RENDERPATH_GL20:
5110                 case RENDERPATH_GLES1:
5111                 case RENDERPATH_GLES2:
5112                         CHECKGLERROR
5113                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5114                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5115                         GL_DepthFunc(GL_ALWAYS);
5116                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5117                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5118                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5119                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5120                         GL_DepthFunc(GL_LEQUAL);
5121                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5122                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5123                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5124                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5125                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5126                         CHECKGLERROR
5127                         break;
5128                 case RENDERPATH_D3D9:
5129                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5130                         break;
5131                 case RENDERPATH_D3D10:
5132                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5133                         break;
5134                 case RENDERPATH_D3D11:
5135                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5136                         break;
5137                 case RENDERPATH_SOFT:
5138                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5139                         break;
5140                 }
5141         }
5142         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5143 }
5144
5145 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5146
5147 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5148 {
5149         vec3_t color;
5150         GLint allpixels = 0, visiblepixels = 0;
5151         // now we have to check the query result
5152         if (rtlight->corona_queryindex_visiblepixels)
5153         {
5154                 switch(vid.renderpath)
5155                 {
5156                 case RENDERPATH_GL11:
5157                 case RENDERPATH_GL13:
5158                 case RENDERPATH_GL20:
5159                 case RENDERPATH_GLES1:
5160                 case RENDERPATH_GLES2:
5161                         CHECKGLERROR
5162                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5163                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5164                         CHECKGLERROR
5165                         break;
5166                 case RENDERPATH_D3D9:
5167                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5168                         break;
5169                 case RENDERPATH_D3D10:
5170                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5171                         break;
5172                 case RENDERPATH_D3D11:
5173                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5174                         break;
5175                 case RENDERPATH_SOFT:
5176                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5177                         break;
5178                 }
5179                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5180                 if (visiblepixels < 1 || allpixels < 1)
5181                         return;
5182                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5183                 cscale *= rtlight->corona_visibility;
5184         }
5185         else
5186         {
5187                 // FIXME: these traces should scan all render entities instead of cl.world
5188                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
5189                         return;
5190         }
5191         VectorScale(rtlight->currentcolor, cscale, color);
5192         if (VectorLength(color) > (1.0f / 256.0f))
5193         {
5194                 float vertex3f[12];
5195                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5196                 if(negated)
5197                 {
5198                         VectorNegate(color, color);
5199                         GL_BlendEquationSubtract(true);
5200                 }
5201                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5202                 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);
5203                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5204                 if(negated)
5205                         GL_BlendEquationSubtract(false);
5206         }
5207 }
5208
5209 void R_Shadow_DrawCoronas(void)
5210 {
5211         int i, flag;
5212         qboolean usequery = false;
5213         size_t lightindex;
5214         dlight_t *light;
5215         rtlight_t *rtlight;
5216         size_t range;
5217         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5218                 return;
5219         if (r_waterstate.renderingscene)
5220                 return;
5221         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5222         R_EntityMatrix(&identitymatrix);
5223
5224         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5225
5226         // check occlusion of coronas
5227         // use GL_ARB_occlusion_query if available
5228         // otherwise use raytraces
5229         r_numqueries = 0;
5230         switch (vid.renderpath)
5231         {
5232         case RENDERPATH_GL11:
5233         case RENDERPATH_GL13:
5234         case RENDERPATH_GL20:
5235         case RENDERPATH_GLES1:
5236         case RENDERPATH_GLES2:
5237                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5238                 if (usequery)
5239                 {
5240                         GL_ColorMask(0,0,0,0);
5241                         if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5242                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5243                         {
5244                                 i = r_maxqueries;
5245                                 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5246                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5247                                 CHECKGLERROR
5248                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5249                                 CHECKGLERROR
5250                         }
5251                         RSurf_ActiveWorldEntity();
5252                         GL_BlendFunc(GL_ONE, GL_ZERO);
5253                         GL_CullFace(GL_NONE);
5254                         GL_DepthMask(false);
5255                         GL_DepthRange(0, 1);
5256                         GL_PolygonOffset(0, 0);
5257                         GL_DepthTest(true);
5258                         R_Mesh_ResetTextureState();
5259                         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, false);
5260                 }
5261                 break;
5262         case RENDERPATH_D3D9:
5263                 usequery = false;
5264                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5265                 break;
5266         case RENDERPATH_D3D10:
5267                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5268                 break;
5269         case RENDERPATH_D3D11:
5270                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5271                 break;
5272         case RENDERPATH_SOFT:
5273                 usequery = false;
5274                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5275                 break;
5276         }
5277         for (lightindex = 0;lightindex < range;lightindex++)
5278         {
5279                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5280                 if (!light)
5281                         continue;
5282                 rtlight = &light->rtlight;
5283                 rtlight->corona_visibility = 0;
5284                 rtlight->corona_queryindex_visiblepixels = 0;
5285                 rtlight->corona_queryindex_allpixels = 0;
5286                 if (!(rtlight->flags & flag))
5287                         continue;
5288                 if (rtlight->corona <= 0)
5289                         continue;
5290                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5291                         continue;
5292                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5293         }
5294         for (i = 0;i < r_refdef.scene.numlights;i++)
5295         {
5296                 rtlight = r_refdef.scene.lights[i];
5297                 rtlight->corona_visibility = 0;
5298                 rtlight->corona_queryindex_visiblepixels = 0;
5299                 rtlight->corona_queryindex_allpixels = 0;
5300                 if (!(rtlight->flags & flag))
5301                         continue;
5302                 if (rtlight->corona <= 0)
5303                         continue;
5304                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5305         }
5306         if (usequery)
5307                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5308
5309         // now draw the coronas using the query data for intensity info
5310         for (lightindex = 0;lightindex < range;lightindex++)
5311         {
5312                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5313                 if (!light)
5314                         continue;
5315                 rtlight = &light->rtlight;
5316                 if (rtlight->corona_visibility <= 0)
5317                         continue;
5318                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5319         }
5320         for (i = 0;i < r_refdef.scene.numlights;i++)
5321         {
5322                 rtlight = r_refdef.scene.lights[i];
5323                 if (rtlight->corona_visibility <= 0)
5324                         continue;
5325                 if (gl_flashblend.integer)
5326                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5327                 else
5328                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5329         }
5330 }
5331
5332
5333
5334 dlight_t *R_Shadow_NewWorldLight(void)
5335 {
5336         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5337 }
5338
5339 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)
5340 {
5341         matrix4x4_t matrix;
5342         // validate parameters
5343         if (style < 0 || style >= MAX_LIGHTSTYLES)
5344         {
5345                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5346                 style = 0;
5347         }
5348         if (!cubemapname)
5349                 cubemapname = "";
5350
5351         // copy to light properties
5352         VectorCopy(origin, light->origin);
5353         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5354         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5355         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5356         /*
5357         light->color[0] = max(color[0], 0);
5358         light->color[1] = max(color[1], 0);
5359         light->color[2] = max(color[2], 0);
5360         */
5361         light->color[0] = color[0];
5362         light->color[1] = color[1];
5363         light->color[2] = color[2];
5364         light->radius = max(radius, 0);
5365         light->style = style;
5366         light->shadow = shadowenable;
5367         light->corona = corona;
5368         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5369         light->coronasizescale = coronasizescale;
5370         light->ambientscale = ambientscale;
5371         light->diffusescale = diffusescale;
5372         light->specularscale = specularscale;
5373         light->flags = flags;
5374
5375         // update renderable light data
5376         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5377         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);
5378 }
5379
5380 void R_Shadow_FreeWorldLight(dlight_t *light)
5381 {
5382         if (r_shadow_selectedlight == light)
5383                 r_shadow_selectedlight = NULL;
5384         R_RTLight_Uncompile(&light->rtlight);
5385         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5386 }
5387
5388 void R_Shadow_ClearWorldLights(void)
5389 {
5390         size_t lightindex;
5391         dlight_t *light;
5392         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5393         for (lightindex = 0;lightindex < range;lightindex++)
5394         {
5395                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5396                 if (light)
5397                         R_Shadow_FreeWorldLight(light);
5398         }
5399         r_shadow_selectedlight = NULL;
5400 }
5401
5402 void R_Shadow_SelectLight(dlight_t *light)
5403 {
5404         if (r_shadow_selectedlight)
5405                 r_shadow_selectedlight->selected = false;
5406         r_shadow_selectedlight = light;
5407         if (r_shadow_selectedlight)
5408                 r_shadow_selectedlight->selected = true;
5409 }
5410
5411 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5412 {
5413         // this is never batched (there can be only one)
5414         float vertex3f[12];
5415         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5416         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5417         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5418 }
5419
5420 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5421 {
5422         float intensity;
5423         float s;
5424         vec3_t spritecolor;
5425         skinframe_t *skinframe;
5426         float vertex3f[12];
5427
5428         // this is never batched (due to the ent parameter changing every time)
5429         // so numsurfaces == 1 and surfacelist[0] == lightnumber
5430         const dlight_t *light = (dlight_t *)ent;
5431         s = EDLIGHTSPRSIZE;
5432
5433         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5434
5435         intensity = 0.5f;
5436         VectorScale(light->color, intensity, spritecolor);
5437         if (VectorLength(spritecolor) < 0.1732f)
5438                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5439         if (VectorLength(spritecolor) > 1.0f)
5440                 VectorNormalize(spritecolor);
5441
5442         // draw light sprite
5443         if (light->cubemapname[0] && !light->shadow)
5444                 skinframe = r_editlights_sprcubemapnoshadowlight;
5445         else if (light->cubemapname[0])
5446                 skinframe = r_editlights_sprcubemaplight;
5447         else if (!light->shadow)
5448                 skinframe = r_editlights_sprnoshadowlight;
5449         else
5450                 skinframe = r_editlights_sprlight;
5451
5452         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);
5453         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5454
5455         // draw selection sprite if light is selected
5456         if (light->selected)
5457         {
5458                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5459                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5460                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5461         }
5462 }
5463
5464 void R_Shadow_DrawLightSprites(void)
5465 {
5466         size_t lightindex;
5467         dlight_t *light;
5468         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5469         for (lightindex = 0;lightindex < range;lightindex++)
5470         {
5471                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5472                 if (light)
5473                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5474         }
5475         if (!r_editlights_lockcursor)
5476                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5477 }
5478
5479 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5480 {
5481         unsigned int range;
5482         dlight_t *light;
5483         rtlight_t *rtlight;
5484         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5485         if (lightindex >= range)
5486                 return -1;
5487         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5488         if (!light)
5489                 return 0;
5490         rtlight = &light->rtlight;
5491         //if (!(rtlight->flags & flag))
5492         //      return 0;
5493         VectorCopy(rtlight->shadoworigin, origin);
5494         *radius = rtlight->radius;
5495         VectorCopy(rtlight->color, color);
5496         return 1;
5497 }
5498
5499 void R_Shadow_SelectLightInView(void)
5500 {
5501         float bestrating, rating, temp[3];
5502         dlight_t *best;
5503         size_t lightindex;
5504         dlight_t *light;
5505         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5506         best = NULL;
5507         bestrating = 0;
5508
5509         if (r_editlights_lockcursor)
5510                 return;
5511         for (lightindex = 0;lightindex < range;lightindex++)
5512         {
5513                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5514                 if (!light)
5515                         continue;
5516                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5517                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5518                 if (rating >= 0.95)
5519                 {
5520                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5521                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5522                         {
5523                                 bestrating = rating;
5524                                 best = light;
5525                         }
5526                 }
5527         }
5528         R_Shadow_SelectLight(best);
5529 }
5530
5531 void R_Shadow_LoadWorldLights(void)
5532 {
5533         int n, a, style, shadow, flags;
5534         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5535         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5536         if (cl.worldmodel == NULL)
5537         {
5538                 Con_Print("No map loaded.\n");
5539                 return;
5540         }
5541         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5542         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5543         if (lightsstring)
5544         {
5545                 s = lightsstring;
5546                 n = 0;
5547                 while (*s)
5548                 {
5549                         t = s;
5550                         /*
5551                         shadow = true;
5552                         for (;COM_Parse(t, true) && strcmp(
5553                         if (COM_Parse(t, true))
5554                         {
5555                                 if (com_token[0] == '!')
5556                                 {
5557                                         shadow = false;
5558                                         origin[0] = atof(com_token+1);
5559                                 }
5560                                 else
5561                                         origin[0] = atof(com_token);
5562                                 if (Com_Parse(t
5563                         }
5564                         */
5565                         t = s;
5566                         while (*s && *s != '\n' && *s != '\r')
5567                                 s++;
5568                         if (!*s)
5569                                 break;
5570                         tempchar = *s;
5571                         shadow = true;
5572                         // check for modifier flags
5573                         if (*t == '!')
5574                         {
5575                                 shadow = false;
5576                                 t++;
5577                         }
5578                         *s = 0;
5579 #if _MSC_VER >= 1400
5580 #define sscanf sscanf_s
5581 #endif
5582                         cubemapname[sizeof(cubemapname)-1] = 0;
5583 #if MAX_QPATH != 128
5584 #error update this code if MAX_QPATH changes
5585 #endif
5586                         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
5587 #if _MSC_VER >= 1400
5588 , sizeof(cubemapname)
5589 #endif
5590 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5591                         *s = tempchar;
5592                         if (a < 18)
5593                                 flags = LIGHTFLAG_REALTIMEMODE;
5594                         if (a < 17)
5595                                 specularscale = 1;
5596                         if (a < 16)
5597                                 diffusescale = 1;
5598                         if (a < 15)
5599                                 ambientscale = 0;
5600                         if (a < 14)
5601                                 coronasizescale = 0.25f;
5602                         if (a < 13)
5603                                 VectorClear(angles);
5604                         if (a < 10)
5605                                 corona = 0;
5606                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5607                                 cubemapname[0] = 0;
5608                         // remove quotes on cubemapname
5609                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5610                         {
5611                                 size_t namelen;
5612                                 namelen = strlen(cubemapname) - 2;
5613                                 memmove(cubemapname, cubemapname + 1, namelen);
5614                                 cubemapname[namelen] = '\0';
5615                         }
5616                         if (a < 8)
5617                         {
5618                                 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);
5619                                 break;
5620                         }
5621                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5622                         if (*s == '\r')
5623                                 s++;
5624                         if (*s == '\n')
5625                                 s++;
5626                         n++;
5627                 }
5628                 if (*s)
5629                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5630                 Mem_Free(lightsstring);
5631         }
5632 }
5633
5634 void R_Shadow_SaveWorldLights(void)
5635 {
5636         size_t lightindex;
5637         dlight_t *light;
5638         size_t bufchars, bufmaxchars;
5639         char *buf, *oldbuf;
5640         char name[MAX_QPATH];
5641         char line[MAX_INPUTLINE];
5642         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5643         // I hate lines which are 3 times my screen size :( --blub
5644         if (!range)
5645                 return;
5646         if (cl.worldmodel == NULL)
5647         {
5648                 Con_Print("No map loaded.\n");
5649                 return;
5650         }
5651         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5652         bufchars = bufmaxchars = 0;
5653         buf = NULL;
5654         for (lightindex = 0;lightindex < range;lightindex++)
5655         {
5656                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5657                 if (!light)
5658                         continue;
5659                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5660                         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);
5661                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5662                         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]);
5663                 else
5664                         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);
5665                 if (bufchars + strlen(line) > bufmaxchars)
5666                 {
5667                         bufmaxchars = bufchars + strlen(line) + 2048;
5668                         oldbuf = buf;
5669                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5670                         if (oldbuf)
5671                         {
5672                                 if (bufchars)
5673                                         memcpy(buf, oldbuf, bufchars);
5674                                 Mem_Free(oldbuf);
5675                         }
5676                 }
5677                 if (strlen(line))
5678                 {
5679                         memcpy(buf + bufchars, line, strlen(line));
5680                         bufchars += strlen(line);
5681                 }
5682         }
5683         if (bufchars)
5684                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5685         if (buf)
5686                 Mem_Free(buf);
5687 }
5688
5689 void R_Shadow_LoadLightsFile(void)
5690 {
5691         int n, a, style;
5692         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5693         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5694         if (cl.worldmodel == NULL)
5695         {
5696                 Con_Print("No map loaded.\n");
5697                 return;
5698         }
5699         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5700         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5701         if (lightsstring)
5702         {
5703                 s = lightsstring;
5704                 n = 0;
5705                 while (*s)
5706                 {
5707                         t = s;
5708                         while (*s && *s != '\n' && *s != '\r')
5709                                 s++;
5710                         if (!*s)
5711                                 break;
5712                         tempchar = *s;
5713                         *s = 0;
5714                         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);
5715                         *s = tempchar;
5716                         if (a < 14)
5717                         {
5718                                 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);
5719                                 break;
5720                         }
5721                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5722                         radius = bound(15, radius, 4096);
5723                         VectorScale(color, (2.0f / (8388608.0f)), color);
5724                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5725                         if (*s == '\r')
5726                                 s++;
5727                         if (*s == '\n')
5728                                 s++;
5729                         n++;
5730                 }
5731                 if (*s)
5732                         Con_Printf("invalid lights file \"%s\"\n", name);
5733                 Mem_Free(lightsstring);
5734         }
5735 }
5736
5737 // tyrlite/hmap2 light types in the delay field
5738 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5739
5740 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5741 {
5742         int entnum;
5743         int style;
5744         int islight;
5745         int skin;
5746         int pflags;
5747         //int effects;
5748         int type;
5749         int n;
5750         char *entfiledata;
5751         const char *data;
5752         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5753         char key[256], value[MAX_INPUTLINE];
5754
5755         if (cl.worldmodel == NULL)
5756         {
5757                 Con_Print("No map loaded.\n");
5758                 return;
5759         }
5760         // try to load a .ent file first
5761         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5762         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5763         // and if that is not found, fall back to the bsp file entity string
5764         if (!data)
5765                 data = cl.worldmodel->brush.entities;
5766         if (!data)
5767                 return;
5768         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5769         {
5770                 type = LIGHTTYPE_MINUSX;
5771                 origin[0] = origin[1] = origin[2] = 0;
5772                 originhack[0] = originhack[1] = originhack[2] = 0;
5773                 angles[0] = angles[1] = angles[2] = 0;
5774                 color[0] = color[1] = color[2] = 1;
5775                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5776                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5777                 fadescale = 1;
5778                 lightscale = 1;
5779                 style = 0;
5780                 skin = 0;
5781                 pflags = 0;
5782                 //effects = 0;
5783                 islight = false;
5784                 while (1)
5785                 {
5786                         if (!COM_ParseToken_Simple(&data, false, false))
5787                                 break; // error
5788                         if (com_token[0] == '}')
5789                                 break; // end of entity
5790                         if (com_token[0] == '_')
5791                                 strlcpy(key, com_token + 1, sizeof(key));
5792                         else
5793                                 strlcpy(key, com_token, sizeof(key));
5794                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5795                                 key[strlen(key)-1] = 0;
5796                         if (!COM_ParseToken_Simple(&data, false, false))
5797                                 break; // error
5798                         strlcpy(value, com_token, sizeof(value));
5799
5800                         // now that we have the key pair worked out...
5801                         if (!strcmp("light", key))
5802                         {
5803                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5804                                 if (n == 1)
5805                                 {
5806                                         // quake
5807                                         light[0] = vec[0] * (1.0f / 256.0f);
5808                                         light[1] = vec[0] * (1.0f / 256.0f);
5809                                         light[2] = vec[0] * (1.0f / 256.0f);
5810                                         light[3] = vec[0];
5811                                 }
5812                                 else if (n == 4)
5813                                 {
5814                                         // halflife
5815                                         light[0] = vec[0] * (1.0f / 255.0f);
5816                                         light[1] = vec[1] * (1.0f / 255.0f);
5817                                         light[2] = vec[2] * (1.0f / 255.0f);
5818                                         light[3] = vec[3];
5819                                 }
5820                         }
5821                         else if (!strcmp("delay", key))
5822                                 type = atoi(value);
5823                         else if (!strcmp("origin", key))
5824                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5825                         else if (!strcmp("angle", key))
5826                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5827                         else if (!strcmp("angles", key))
5828                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5829                         else if (!strcmp("color", key))
5830                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5831                         else if (!strcmp("wait", key))
5832                                 fadescale = atof(value);
5833                         else if (!strcmp("classname", key))
5834                         {
5835                                 if (!strncmp(value, "light", 5))
5836                                 {
5837                                         islight = true;
5838                                         if (!strcmp(value, "light_fluoro"))
5839                                         {
5840                                                 originhack[0] = 0;
5841                                                 originhack[1] = 0;
5842                                                 originhack[2] = 0;
5843                                                 overridecolor[0] = 1;
5844                                                 overridecolor[1] = 1;
5845                                                 overridecolor[2] = 1;
5846                                         }
5847                                         if (!strcmp(value, "light_fluorospark"))
5848                                         {
5849                                                 originhack[0] = 0;
5850                                                 originhack[1] = 0;
5851                                                 originhack[2] = 0;
5852                                                 overridecolor[0] = 1;
5853                                                 overridecolor[1] = 1;
5854                                                 overridecolor[2] = 1;
5855                                         }
5856                                         if (!strcmp(value, "light_globe"))
5857                                         {
5858                                                 originhack[0] = 0;
5859                                                 originhack[1] = 0;
5860                                                 originhack[2] = 0;
5861                                                 overridecolor[0] = 1;
5862                                                 overridecolor[1] = 0.8;
5863                                                 overridecolor[2] = 0.4;
5864                                         }
5865                                         if (!strcmp(value, "light_flame_large_yellow"))
5866                                         {
5867                                                 originhack[0] = 0;
5868                                                 originhack[1] = 0;
5869                                                 originhack[2] = 0;
5870                                                 overridecolor[0] = 1;
5871                                                 overridecolor[1] = 0.5;
5872                                                 overridecolor[2] = 0.1;
5873                                         }
5874                                         if (!strcmp(value, "light_flame_small_yellow"))
5875                                         {
5876                                                 originhack[0] = 0;
5877                                                 originhack[1] = 0;
5878                                                 originhack[2] = 0;
5879                                                 overridecolor[0] = 1;
5880                                                 overridecolor[1] = 0.5;
5881                                                 overridecolor[2] = 0.1;
5882                                         }
5883                                         if (!strcmp(value, "light_torch_small_white"))
5884                                         {
5885                                                 originhack[0] = 0;
5886                                                 originhack[1] = 0;
5887                                                 originhack[2] = 0;
5888                                                 overridecolor[0] = 1;
5889                                                 overridecolor[1] = 0.5;
5890                                                 overridecolor[2] = 0.1;
5891                                         }
5892                                         if (!strcmp(value, "light_torch_small_walltorch"))
5893                                         {
5894                                                 originhack[0] = 0;
5895                                                 originhack[1] = 0;
5896                                                 originhack[2] = 0;
5897                                                 overridecolor[0] = 1;
5898                                                 overridecolor[1] = 0.5;
5899                                                 overridecolor[2] = 0.1;
5900                                         }
5901                                 }
5902                         }
5903                         else if (!strcmp("style", key))
5904                                 style = atoi(value);
5905                         else if (!strcmp("skin", key))
5906                                 skin = (int)atof(value);
5907                         else if (!strcmp("pflags", key))
5908                                 pflags = (int)atof(value);
5909                         //else if (!strcmp("effects", key))
5910                         //      effects = (int)atof(value);
5911                         else if (cl.worldmodel->type == mod_brushq3)
5912                         {
5913                                 if (!strcmp("scale", key))
5914                                         lightscale = atof(value);
5915                                 if (!strcmp("fade", key))
5916                                         fadescale = atof(value);
5917                         }
5918                 }
5919                 if (!islight)
5920                         continue;
5921                 if (lightscale <= 0)
5922                         lightscale = 1;
5923                 if (fadescale <= 0)
5924                         fadescale = 1;
5925                 if (color[0] == color[1] && color[0] == color[2])
5926                 {
5927                         color[0] *= overridecolor[0];
5928                         color[1] *= overridecolor[1];
5929                         color[2] *= overridecolor[2];
5930                 }
5931                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5932                 color[0] = color[0] * light[0];
5933                 color[1] = color[1] * light[1];
5934                 color[2] = color[2] * light[2];
5935                 switch (type)
5936                 {
5937                 case LIGHTTYPE_MINUSX:
5938                         break;
5939                 case LIGHTTYPE_RECIPX:
5940                         radius *= 2;
5941                         VectorScale(color, (1.0f / 16.0f), color);
5942                         break;
5943                 case LIGHTTYPE_RECIPXX:
5944                         radius *= 2;
5945                         VectorScale(color, (1.0f / 16.0f), color);
5946                         break;
5947                 default:
5948                 case LIGHTTYPE_NONE:
5949                         break;
5950                 case LIGHTTYPE_SUN:
5951                         break;
5952                 case LIGHTTYPE_MINUSXX:
5953                         break;
5954                 }
5955                 VectorAdd(origin, originhack, origin);
5956                 if (radius >= 1)
5957                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5958         }
5959         if (entfiledata)
5960                 Mem_Free(entfiledata);
5961 }
5962
5963
5964 void R_Shadow_SetCursorLocationForView(void)
5965 {
5966         vec_t dist, push;
5967         vec3_t dest, endpos;
5968         trace_t trace;
5969         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5970         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5971         if (trace.fraction < 1)
5972         {
5973                 dist = trace.fraction * r_editlights_cursordistance.value;
5974                 push = r_editlights_cursorpushback.value;
5975                 if (push > dist)
5976                         push = dist;
5977                 push = -push;
5978                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5979                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5980         }
5981         else
5982         {
5983                 VectorClear( endpos );
5984         }
5985         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5986         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5987         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5988 }
5989
5990 void R_Shadow_UpdateWorldLightSelection(void)
5991 {
5992         if (r_editlights.integer)
5993         {
5994                 R_Shadow_SetCursorLocationForView();
5995                 R_Shadow_SelectLightInView();
5996         }
5997         else
5998                 R_Shadow_SelectLight(NULL);
5999 }
6000
6001 void R_Shadow_EditLights_Clear_f(void)
6002 {
6003         R_Shadow_ClearWorldLights();
6004 }
6005
6006 void R_Shadow_EditLights_Reload_f(void)
6007 {
6008         if (!cl.worldmodel)
6009                 return;
6010         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6011         R_Shadow_ClearWorldLights();
6012         R_Shadow_LoadWorldLights();
6013         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6014         {
6015                 R_Shadow_LoadLightsFile();
6016                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6017                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6018         }
6019 }
6020
6021 void R_Shadow_EditLights_Save_f(void)
6022 {
6023         if (!cl.worldmodel)
6024                 return;
6025         R_Shadow_SaveWorldLights();
6026 }
6027
6028 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6029 {
6030         R_Shadow_ClearWorldLights();
6031         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6032 }
6033
6034 void R_Shadow_EditLights_ImportLightsFile_f(void)
6035 {
6036         R_Shadow_ClearWorldLights();
6037         R_Shadow_LoadLightsFile();
6038 }
6039
6040 void R_Shadow_EditLights_Spawn_f(void)
6041 {
6042         vec3_t color;
6043         if (!r_editlights.integer)
6044         {
6045                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6046                 return;
6047         }
6048         if (Cmd_Argc() != 1)
6049         {
6050                 Con_Print("r_editlights_spawn does not take parameters\n");
6051                 return;
6052         }
6053         color[0] = color[1] = color[2] = 1;
6054         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6055 }
6056
6057 void R_Shadow_EditLights_Edit_f(void)
6058 {
6059         vec3_t origin, angles, color;
6060         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6061         int style, shadows, flags, normalmode, realtimemode;
6062         char cubemapname[MAX_INPUTLINE];
6063         if (!r_editlights.integer)
6064         {
6065                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6066                 return;
6067         }
6068         if (!r_shadow_selectedlight)
6069         {
6070                 Con_Print("No selected light.\n");
6071                 return;
6072         }
6073         VectorCopy(r_shadow_selectedlight->origin, origin);
6074         VectorCopy(r_shadow_selectedlight->angles, angles);
6075         VectorCopy(r_shadow_selectedlight->color, color);
6076         radius = r_shadow_selectedlight->radius;
6077         style = r_shadow_selectedlight->style;
6078         if (r_shadow_selectedlight->cubemapname)
6079                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6080         else
6081                 cubemapname[0] = 0;
6082         shadows = r_shadow_selectedlight->shadow;
6083         corona = r_shadow_selectedlight->corona;
6084         coronasizescale = r_shadow_selectedlight->coronasizescale;
6085         ambientscale = r_shadow_selectedlight->ambientscale;
6086         diffusescale = r_shadow_selectedlight->diffusescale;
6087         specularscale = r_shadow_selectedlight->specularscale;
6088         flags = r_shadow_selectedlight->flags;
6089         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6090         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6091         if (!strcmp(Cmd_Argv(1), "origin"))
6092         {
6093                 if (Cmd_Argc() != 5)
6094                 {
6095                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6096                         return;
6097                 }
6098                 origin[0] = atof(Cmd_Argv(2));
6099                 origin[1] = atof(Cmd_Argv(3));
6100                 origin[2] = atof(Cmd_Argv(4));
6101         }
6102         else if (!strcmp(Cmd_Argv(1), "originscale"))
6103         {
6104                 if (Cmd_Argc() != 5)
6105                 {
6106                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6107                         return;
6108                 }
6109                 origin[0] *= atof(Cmd_Argv(2));
6110                 origin[1] *= atof(Cmd_Argv(3));
6111                 origin[2] *= atof(Cmd_Argv(4));
6112         }
6113         else if (!strcmp(Cmd_Argv(1), "originx"))
6114         {
6115                 if (Cmd_Argc() != 3)
6116                 {
6117                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6118                         return;
6119                 }
6120                 origin[0] = atof(Cmd_Argv(2));
6121         }
6122         else if (!strcmp(Cmd_Argv(1), "originy"))
6123         {
6124                 if (Cmd_Argc() != 3)
6125                 {
6126                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6127                         return;
6128                 }
6129                 origin[1] = atof(Cmd_Argv(2));
6130         }
6131         else if (!strcmp(Cmd_Argv(1), "originz"))
6132         {
6133                 if (Cmd_Argc() != 3)
6134                 {
6135                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6136                         return;
6137                 }
6138                 origin[2] = atof(Cmd_Argv(2));
6139         }
6140         else if (!strcmp(Cmd_Argv(1), "move"))
6141         {
6142                 if (Cmd_Argc() != 5)
6143                 {
6144                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6145                         return;
6146                 }
6147                 origin[0] += atof(Cmd_Argv(2));
6148                 origin[1] += atof(Cmd_Argv(3));
6149                 origin[2] += atof(Cmd_Argv(4));
6150         }
6151         else if (!strcmp(Cmd_Argv(1), "movex"))
6152         {
6153                 if (Cmd_Argc() != 3)
6154                 {
6155                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6156                         return;
6157                 }
6158                 origin[0] += atof(Cmd_Argv(2));
6159         }
6160         else if (!strcmp(Cmd_Argv(1), "movey"))
6161         {
6162                 if (Cmd_Argc() != 3)
6163                 {
6164                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6165                         return;
6166                 }
6167                 origin[1] += atof(Cmd_Argv(2));
6168         }
6169         else if (!strcmp(Cmd_Argv(1), "movez"))
6170         {
6171                 if (Cmd_Argc() != 3)
6172                 {
6173                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6174                         return;
6175                 }
6176                 origin[2] += atof(Cmd_Argv(2));
6177         }
6178         else if (!strcmp(Cmd_Argv(1), "angles"))
6179         {
6180                 if (Cmd_Argc() != 5)
6181                 {
6182                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6183                         return;
6184                 }
6185                 angles[0] = atof(Cmd_Argv(2));
6186                 angles[1] = atof(Cmd_Argv(3));
6187                 angles[2] = atof(Cmd_Argv(4));
6188         }
6189         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6190         {
6191                 if (Cmd_Argc() != 3)
6192                 {
6193                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6194                         return;
6195                 }
6196                 angles[0] = atof(Cmd_Argv(2));
6197         }
6198         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6199         {
6200                 if (Cmd_Argc() != 3)
6201                 {
6202                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6203                         return;
6204                 }
6205                 angles[1] = atof(Cmd_Argv(2));
6206         }
6207         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6208         {
6209                 if (Cmd_Argc() != 3)
6210                 {
6211                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6212                         return;
6213                 }
6214                 angles[2] = atof(Cmd_Argv(2));
6215         }
6216         else if (!strcmp(Cmd_Argv(1), "color"))
6217         {
6218                 if (Cmd_Argc() != 5)
6219                 {
6220                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6221                         return;
6222                 }
6223                 color[0] = atof(Cmd_Argv(2));
6224                 color[1] = atof(Cmd_Argv(3));
6225                 color[2] = atof(Cmd_Argv(4));
6226         }
6227         else if (!strcmp(Cmd_Argv(1), "radius"))
6228         {
6229                 if (Cmd_Argc() != 3)
6230                 {
6231                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6232                         return;
6233                 }
6234                 radius = atof(Cmd_Argv(2));
6235         }
6236         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6237         {
6238                 if (Cmd_Argc() == 3)
6239                 {
6240                         double scale = atof(Cmd_Argv(2));
6241                         color[0] *= scale;
6242                         color[1] *= scale;
6243                         color[2] *= scale;
6244                 }
6245                 else
6246                 {
6247                         if (Cmd_Argc() != 5)
6248                         {
6249                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
6250                                 return;
6251                         }
6252                         color[0] *= atof(Cmd_Argv(2));
6253                         color[1] *= atof(Cmd_Argv(3));
6254                         color[2] *= atof(Cmd_Argv(4));
6255                 }
6256         }
6257         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6258         {
6259                 if (Cmd_Argc() != 3)
6260                 {
6261                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6262                         return;
6263                 }
6264                 radius *= atof(Cmd_Argv(2));
6265         }
6266         else if (!strcmp(Cmd_Argv(1), "style"))
6267         {
6268                 if (Cmd_Argc() != 3)
6269                 {
6270                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6271                         return;
6272                 }
6273                 style = atoi(Cmd_Argv(2));
6274         }
6275         else if (!strcmp(Cmd_Argv(1), "cubemap"))
6276         {
6277                 if (Cmd_Argc() > 3)
6278                 {
6279                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6280                         return;
6281                 }
6282                 if (Cmd_Argc() == 3)
6283                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6284                 else
6285                         cubemapname[0] = 0;
6286         }
6287         else if (!strcmp(Cmd_Argv(1), "shadows"))
6288         {
6289                 if (Cmd_Argc() != 3)
6290                 {
6291                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6292                         return;
6293                 }
6294                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6295         }
6296         else if (!strcmp(Cmd_Argv(1), "corona"))
6297         {
6298                 if (Cmd_Argc() != 3)
6299                 {
6300                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6301                         return;
6302                 }
6303                 corona = atof(Cmd_Argv(2));
6304         }
6305         else if (!strcmp(Cmd_Argv(1), "coronasize"))
6306         {
6307                 if (Cmd_Argc() != 3)
6308                 {
6309                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6310                         return;
6311                 }
6312                 coronasizescale = atof(Cmd_Argv(2));
6313         }
6314         else if (!strcmp(Cmd_Argv(1), "ambient"))
6315         {
6316                 if (Cmd_Argc() != 3)
6317                 {
6318                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6319                         return;
6320                 }
6321                 ambientscale = atof(Cmd_Argv(2));
6322         }
6323         else if (!strcmp(Cmd_Argv(1), "diffuse"))
6324         {
6325                 if (Cmd_Argc() != 3)
6326                 {
6327                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6328                         return;
6329                 }
6330                 diffusescale = atof(Cmd_Argv(2));
6331         }
6332         else if (!strcmp(Cmd_Argv(1), "specular"))
6333         {
6334                 if (Cmd_Argc() != 3)
6335                 {
6336                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6337                         return;
6338                 }
6339                 specularscale = atof(Cmd_Argv(2));
6340         }
6341         else if (!strcmp(Cmd_Argv(1), "normalmode"))
6342         {
6343                 if (Cmd_Argc() != 3)
6344                 {
6345                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6346                         return;
6347                 }
6348                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6349         }
6350         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6351         {
6352                 if (Cmd_Argc() != 3)
6353                 {
6354                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6355                         return;
6356                 }
6357                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6358         }
6359         else
6360         {
6361                 Con_Print("usage: r_editlights_edit [property] [value]\n");
6362                 Con_Print("Selected light's properties:\n");
6363                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6364                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6365                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6366                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
6367                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
6368                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
6369                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6370                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
6371                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
6372                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
6373                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
6374                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
6375                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6376                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6377                 return;
6378         }
6379         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6380         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6381 }
6382
6383 void R_Shadow_EditLights_EditAll_f(void)
6384 {
6385         size_t lightindex;
6386         dlight_t *light, *oldselected;
6387         size_t range;
6388
6389         if (!r_editlights.integer)
6390         {
6391                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6392                 return;
6393         }
6394
6395         oldselected = r_shadow_selectedlight;
6396         // EditLights doesn't seem to have a "remove" command or something so:
6397         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6398         for (lightindex = 0;lightindex < range;lightindex++)
6399         {
6400                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6401                 if (!light)
6402                         continue;
6403                 R_Shadow_SelectLight(light);
6404                 R_Shadow_EditLights_Edit_f();
6405         }
6406         // return to old selected (to not mess editing once selection is locked)
6407         R_Shadow_SelectLight(oldselected);
6408 }
6409
6410 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6411 {
6412         int lightnumber, lightcount;
6413         size_t lightindex, range;
6414         dlight_t *light;
6415         float x, y;
6416         char temp[256];
6417         if (!r_editlights.integer)
6418                 return;
6419         x = vid_conwidth.value - 240;
6420         y = 5;
6421         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6422         lightnumber = -1;
6423         lightcount = 0;
6424         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6425         for (lightindex = 0;lightindex < range;lightindex++)
6426         {
6427                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6428                 if (!light)
6429                         continue;
6430                 if (light == r_shadow_selectedlight)
6431                         lightnumber = lightindex;
6432                 lightcount++;
6433         }
6434         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;
6435         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;
6436         y += 8;
6437         if (r_shadow_selectedlight == NULL)
6438                 return;
6439         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;
6440         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;
6441         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;
6442         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;
6443         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;
6444         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;
6445         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;
6446         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;
6447         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;
6448         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;
6449         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;
6450         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;
6451         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;
6452         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;
6453         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;
6454 }
6455
6456 void R_Shadow_EditLights_ToggleShadow_f(void)
6457 {
6458         if (!r_editlights.integer)
6459         {
6460                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6461                 return;
6462         }
6463         if (!r_shadow_selectedlight)
6464         {
6465                 Con_Print("No selected light.\n");
6466                 return;
6467         }
6468         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);
6469 }
6470
6471 void R_Shadow_EditLights_ToggleCorona_f(void)
6472 {
6473         if (!r_editlights.integer)
6474         {
6475                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6476                 return;
6477         }
6478         if (!r_shadow_selectedlight)
6479         {
6480                 Con_Print("No selected light.\n");
6481                 return;
6482         }
6483         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);
6484 }
6485
6486 void R_Shadow_EditLights_Remove_f(void)
6487 {
6488         if (!r_editlights.integer)
6489         {
6490                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
6491                 return;
6492         }
6493         if (!r_shadow_selectedlight)
6494         {
6495                 Con_Print("No selected light.\n");
6496                 return;
6497         }
6498         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6499         r_shadow_selectedlight = NULL;
6500 }
6501
6502 void R_Shadow_EditLights_Help_f(void)
6503 {
6504         Con_Print(
6505 "Documentation on r_editlights system:\n"
6506 "Settings:\n"
6507 "r_editlights : enable/disable editing mode\n"
6508 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6509 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6510 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6511 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6512 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6513 "Commands:\n"
6514 "r_editlights_help : this help\n"
6515 "r_editlights_clear : remove all lights\n"
6516 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6517 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6518 "r_editlights_save : save to .rtlights file\n"
6519 "r_editlights_spawn : create a light with default settings\n"
6520 "r_editlights_edit command : edit selected light - more documentation below\n"
6521 "r_editlights_remove : remove selected light\n"
6522 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6523 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6524 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6525 "Edit commands:\n"
6526 "origin x y z : set light location\n"
6527 "originx x: set x component of light location\n"
6528 "originy y: set y component of light location\n"
6529 "originz z: set z component of light location\n"
6530 "move x y z : adjust light location\n"
6531 "movex x: adjust x component of light location\n"
6532 "movey y: adjust y component of light location\n"
6533 "movez z: adjust z component of light location\n"
6534 "angles x y z : set light angles\n"
6535 "anglesx x: set x component of light angles\n"
6536 "anglesy y: set y component of light angles\n"
6537 "anglesz z: set z component of light angles\n"
6538 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6539 "radius radius : set radius (size) of light\n"
6540 "colorscale grey : multiply color of light (1 does nothing)\n"
6541 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6542 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6543 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6544 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6545 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6546 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6547 "shadows 1/0 : turn on/off shadows\n"
6548 "corona n : set corona intensity\n"
6549 "coronasize n : set corona size (0-1)\n"
6550 "ambient n : set ambient intensity (0-1)\n"
6551 "diffuse n : set diffuse intensity (0-1)\n"
6552 "specular n : set specular intensity (0-1)\n"
6553 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6554 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6555 "<nothing> : print light properties to console\n"
6556         );
6557 }
6558
6559 void R_Shadow_EditLights_CopyInfo_f(void)
6560 {
6561         if (!r_editlights.integer)
6562         {
6563                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6564                 return;
6565         }
6566         if (!r_shadow_selectedlight)
6567         {
6568                 Con_Print("No selected light.\n");
6569                 return;
6570         }
6571         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6572         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6573         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6574         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6575         if (r_shadow_selectedlight->cubemapname)
6576                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6577         else
6578                 r_shadow_bufferlight.cubemapname[0] = 0;
6579         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6580         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6581         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6582         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6583         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6584         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6585         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6586 }
6587
6588 void R_Shadow_EditLights_PasteInfo_f(void)
6589 {
6590         if (!r_editlights.integer)
6591         {
6592                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6593                 return;
6594         }
6595         if (!r_shadow_selectedlight)
6596         {
6597                 Con_Print("No selected light.\n");
6598                 return;
6599         }
6600         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);
6601 }
6602
6603 void R_Shadow_EditLights_Lock_f(void)
6604 {
6605         if (!r_editlights.integer)
6606         {
6607                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6608                 return;
6609         }
6610         if (r_editlights_lockcursor)
6611         {
6612                 r_editlights_lockcursor = false;
6613                 return;
6614         }
6615         if (!r_shadow_selectedlight)
6616         {
6617                 Con_Print("No selected light to lock on.\n");
6618                 return;
6619         }
6620         r_editlights_lockcursor = true;
6621 }
6622
6623 void R_Shadow_EditLights_Init(void)
6624 {
6625         Cvar_RegisterVariable(&r_editlights);
6626         Cvar_RegisterVariable(&r_editlights_cursordistance);
6627         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6628         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6629         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6630         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6631         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6632         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6633         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)");
6634         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6635         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6636         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6637         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)");
6638         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6639         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6640         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6641         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6642         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6643         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6644         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)");
6645         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6646 }
6647
6648
6649
6650 /*
6651 =============================================================================
6652
6653 LIGHT SAMPLING
6654
6655 =============================================================================
6656 */
6657
6658 void R_LightPoint(vec3_t color, const vec3_t p, const int flags)
6659 {
6660         int i, numlights, flag;
6661         float f, relativepoint[3], dist, dist2, lightradius2;
6662         vec3_t diffuse, n;
6663         rtlight_t *light;
6664         dlight_t *dlight;
6665
6666         if (r_fullbright.integer)
6667         {
6668                 VectorSet(color, 1, 1, 1);
6669                 return;
6670         }
6671
6672         VectorClear(color);
6673
6674         if (flags & LP_LIGHTMAP)
6675         {
6676                 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6677                 {
6678                         VectorClear(diffuse);
6679                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6680                         VectorAdd(color, diffuse, color);
6681                 }
6682                 else
6683                         VectorSet(color, 1, 1, 1);
6684                 color[0] += r_refdef.scene.ambient;
6685                 color[1] += r_refdef.scene.ambient;
6686                 color[2] += r_refdef.scene.ambient;
6687         }
6688
6689         if (flags & LP_RTWORLD)
6690         {
6691                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6692                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6693                 for (i = 0; i < numlights; i++)
6694                 {
6695                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6696                         if (!dlight)
6697                                 continue;
6698                         light = &dlight->rtlight;
6699                         if (!(light->flags & flag))
6700                                 continue;
6701                         // sample
6702                         lightradius2 = light->radius * light->radius;
6703                         VectorSubtract(light->shadoworigin, p, relativepoint);
6704                         dist2 = VectorLength2(relativepoint);
6705                         if (dist2 >= lightradius2)
6706                                 continue;
6707                         dist = sqrt(dist2) / light->radius;
6708                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6709                         if (f <= 0)
6710                                 continue;
6711                         // todo: add to both ambient and diffuse
6712                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6713                                 VectorMA(color, f, light->currentcolor, color);
6714                 }
6715         }
6716         if (flags & LP_DYNLIGHT)
6717         {
6718                 // sample dlights
6719                 for (i = 0;i < r_refdef.scene.numlights;i++)
6720                 {
6721                         light = r_refdef.scene.lights[i];
6722                         // sample
6723                         lightradius2 = light->radius * light->radius;
6724                         VectorSubtract(light->shadoworigin, p, relativepoint);
6725                         dist2 = VectorLength2(relativepoint);
6726                         if (dist2 >= lightradius2)
6727                                 continue;
6728                         dist = sqrt(dist2) / light->radius;
6729                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6730                         if (f <= 0)
6731                                 continue;
6732                         // todo: add to both ambient and diffuse
6733                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6734                                 VectorMA(color, f, light->color, color);
6735                 }
6736         }
6737 }
6738
6739 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6740 {
6741         int i, numlights, flag;
6742         rtlight_t *light;
6743         dlight_t *dlight;
6744         float relativepoint[3];
6745         float color[3];
6746         float dir[3];
6747         float dist;
6748         float dist2;
6749         float intensity;
6750         float sample[5*3];
6751         float lightradius2;
6752
6753         if (r_fullbright.integer)
6754         {
6755                 VectorSet(ambient, 1, 1, 1);
6756                 VectorClear(diffuse);
6757                 VectorClear(lightdir);
6758                 return;
6759         }
6760
6761         if (flags == LP_LIGHTMAP)
6762         {
6763                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6764                 VectorClear(diffuse);
6765                 VectorClear(lightdir);
6766                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6767                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6768                 else
6769                         VectorSet(ambient, 1, 1, 1);
6770                 return;
6771         }
6772
6773         memset(sample, 0, sizeof(sample));
6774         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6775
6776         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6777         {
6778                 vec3_t tempambient;
6779                 VectorClear(tempambient);
6780                 VectorClear(color);
6781                 VectorClear(relativepoint);
6782                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6783                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6784                 VectorScale(color, r_refdef.lightmapintensity, color);
6785                 VectorAdd(sample, tempambient, sample);
6786                 VectorMA(sample    , 0.5f            , color, sample    );
6787                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6788                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6789                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6790                 // calculate a weighted average light direction as well
6791                 intensity = VectorLength(color);
6792                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6793         }
6794
6795         if (flags & LP_RTWORLD)
6796         {
6797                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6798                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6799                 for (i = 0; i < numlights; i++)
6800                 {
6801                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6802                         if (!dlight)
6803                                 continue;
6804                         light = &dlight->rtlight;
6805                         if (!(light->flags & flag))
6806                                 continue;
6807                         // sample
6808                         lightradius2 = light->radius * light->radius;
6809                         VectorSubtract(light->shadoworigin, p, relativepoint);
6810                         dist2 = VectorLength2(relativepoint);
6811                         if (dist2 >= lightradius2)
6812                                 continue;
6813                         dist = sqrt(dist2) / light->radius;
6814                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6815                         if (intensity <= 0.0f)
6816                                 continue;
6817                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6818                                 continue;
6819                         // scale down intensity to add to both ambient and diffuse
6820                         //intensity *= 0.5f;
6821                         VectorNormalize(relativepoint);
6822                         VectorScale(light->currentcolor, intensity, color);
6823                         VectorMA(sample    , 0.5f            , color, sample    );
6824                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6825                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6826                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6827                         // calculate a weighted average light direction as well
6828                         intensity *= VectorLength(color);
6829                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6830                 }
6831                 // FIXME: sample bouncegrid too!
6832         }
6833
6834         if (flags & LP_DYNLIGHT)
6835         {
6836                 // sample dlights
6837                 for (i = 0;i < r_refdef.scene.numlights;i++)
6838                 {
6839                         light = r_refdef.scene.lights[i];
6840                         // sample
6841                         lightradius2 = light->radius * light->radius;
6842                         VectorSubtract(light->shadoworigin, p, relativepoint);
6843                         dist2 = VectorLength2(relativepoint);
6844                         if (dist2 >= lightradius2)
6845                                 continue;
6846                         dist = sqrt(dist2) / light->radius;
6847                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6848                         if (intensity <= 0.0f)
6849                                 continue;
6850                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6851                                 continue;
6852                         // scale down intensity to add to both ambient and diffuse
6853                         //intensity *= 0.5f;
6854                         VectorNormalize(relativepoint);
6855                         VectorScale(light->currentcolor, intensity, color);
6856                         VectorMA(sample    , 0.5f            , color, sample    );
6857                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6858                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6859                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6860                         // calculate a weighted average light direction as well
6861                         intensity *= VectorLength(color);
6862                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6863                 }
6864         }
6865
6866         // calculate the direction we'll use to reduce the sample to a directional light source
6867         VectorCopy(sample + 12, dir);
6868         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6869         VectorNormalize(dir);
6870         // extract the diffuse color along the chosen direction and scale it
6871         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6872         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6873         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6874         // subtract some of diffuse from ambient
6875         VectorMA(sample, -0.333f, diffuse, ambient);
6876         // store the normalized lightdir
6877         VectorCopy(dir, lightdir);
6878 }