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