]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
better detection of active rtlights in bouncegrid code
[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 && r_shadow_bouncegrid_static.integer)
2391         {
2392                 enable = false;
2393                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2394                 for (lightindex = 0;lightindex < range;lightindex++)
2395                 {
2396                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2397                         if (!light || !(light->flags & flag))
2398                                 continue;
2399                         rtlight = &light->rtlight;
2400                         // when static, we skip styled lights because they tend to change...
2401                         if (rtlight->style > 0)
2402                                 continue;
2403                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2404                         if (!VectorLength2(lightcolor))
2405                                 continue;
2406                         enable = true;
2407                         break;
2408                 }
2409         }
2410
2411         if (!enable)
2412         {
2413                 if (r_shadow_bouncegridtexture)
2414                 {
2415                         R_FreeTexture(r_shadow_bouncegridtexture);
2416                         r_shadow_bouncegridtexture = NULL;
2417                 }
2418                 if (r_shadow_bouncegridpixels)
2419                         Mem_Free(r_shadow_bouncegridpixels);
2420                 r_shadow_bouncegridpixels = NULL;
2421                 if (r_shadow_bouncegridhighpixels)
2422                         Mem_Free(r_shadow_bouncegridhighpixels);
2423                 r_shadow_bouncegridhighpixels = NULL;
2424                 r_shadow_bouncegridnumpixels = 0;
2425                 r_shadow_bouncegriddirectional = false;
2426                 return;
2427         }
2428
2429         // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2430         settings.staticmode                    = r_shadow_bouncegrid_static.integer != 0;
2431         settings.bounceanglediffuse            = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2432         settings.directionalshading            = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2433         settings.dlightparticlemultiplier      = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2434         settings.hitmodels                     = r_shadow_bouncegrid_hitmodels.integer != 0;
2435         settings.lightradiusscale              = r_shadow_bouncegrid_lightradiusscale.value;
2436         settings.maxbounce                     = r_shadow_bouncegrid_maxbounce.integer;
2437         settings.particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
2438         settings.particleintensity             = r_shadow_bouncegrid_particleintensity.value;
2439         settings.photons                       = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2440         settings.spacing[0]                    = r_shadow_bouncegrid_spacingx.value;
2441         settings.spacing[1]                    = r_shadow_bouncegrid_spacingy.value;
2442         settings.spacing[2]                    = r_shadow_bouncegrid_spacingz.value;
2443         settings.stablerandom                  = r_shadow_bouncegrid_stablerandom.integer;
2444
2445         // bound the values for sanity
2446         settings.photons = bound(1, settings.photons, 1048576);
2447         settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2448         settings.maxbounce = bound(1, settings.maxbounce, 16);
2449         settings.spacing[0] = bound(1, settings.spacing[0], 512);
2450         settings.spacing[1] = bound(1, settings.spacing[1], 512);
2451         settings.spacing[2] = bound(1, settings.spacing[2], 512);
2452
2453         // get the spacing values
2454         spacing[0] = settings.spacing[0];
2455         spacing[1] = settings.spacing[1];
2456         spacing[2] = settings.spacing[2];
2457         ispacing[0] = 1.0f / spacing[0];
2458         ispacing[1] = 1.0f / spacing[1];
2459         ispacing[2] = 1.0f / spacing[2];
2460
2461         // calculate texture size enclosing entire world bounds at the spacing
2462         VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2463         VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2464         VectorSubtract(maxs, mins, size);
2465         // now we can calculate the resolution we want
2466         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2467         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2468         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2469         // figure out the exact texture size (honoring power of 2 if required)
2470         c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2471         c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2472         c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2473         if (vid.support.arb_texture_non_power_of_two)
2474         {
2475                 resolution[0] = c[0];
2476                 resolution[1] = c[1];
2477                 resolution[2] = c[2];
2478         }
2479         else
2480         {
2481                 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2482                 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2483                 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2484         }
2485         size[0] = spacing[0] * resolution[0];
2486         size[1] = spacing[1] * resolution[1];
2487         size[2] = spacing[2] * resolution[2];
2488
2489         // if dynamic we may or may not want to use the world bounds
2490         // if the dynamic size is smaller than the world bounds, use it instead
2491         if (!settings.staticmode && (r_shadow_bouncegrid_x.integer < resolution[0] || r_shadow_bouncegrid_y.integer < resolution[1] || r_shadow_bouncegrid_z.integer < resolution[2]))
2492         {
2493                 // we know the resolution we want
2494                 c[0] = r_shadow_bouncegrid_x.integer;
2495                 c[1] = r_shadow_bouncegrid_y.integer;
2496                 c[2] = r_shadow_bouncegrid_z.integer;
2497                 // now we can calculate the texture size (power of 2 if required)
2498                 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2499                 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2500                 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2501                 if (vid.support.arb_texture_non_power_of_two)
2502                 {
2503                         resolution[0] = c[0];
2504                         resolution[1] = c[1];
2505                         resolution[2] = c[2];
2506                 }
2507                 else
2508                 {
2509                         for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2510                         for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2511                         for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2512                 }
2513                 size[0] = spacing[0] * resolution[0];
2514                 size[1] = spacing[1] * resolution[1];
2515                 size[2] = spacing[2] * resolution[2];
2516                 // center the rendering on the view
2517                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2518                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2519                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2520         }
2521
2522         // recalculate the maxs in case the resolution was not satisfactory
2523         VectorAdd(mins, size, maxs);
2524
2525         // if all the settings seem identical to the previous update, return
2526         if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2527                 return;
2528
2529         // store the new settings
2530         r_shadow_bouncegridsettings = settings;
2531
2532         // we're going to update the bouncegrid, update the matrix...
2533         memset(m, 0, sizeof(m));
2534         m[0] = 1.0f / size[0];
2535         m[3] = -mins[0] * m[0];
2536         m[5] = 1.0f / size[1];
2537         m[7] = -mins[1] * m[5];
2538         m[10] = 1.0f / size[2];
2539         m[11] = -mins[2] * m[10];
2540         m[15] = 1.0f;
2541         if (settings.directionalshading)
2542         {
2543                 m[10] *= 0.25f;
2544                 m[11] *= 0.25f;
2545         }
2546         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2547         numpixels = resolution[0]*resolution[1]*resolution[2];
2548         if (settings.directionalshading)
2549                 numpixels *= 4;
2550         r_shadow_bouncegriddirectional = settings.directionalshading;
2551         // reallocate pixels for this update if needed...
2552         if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2553         {
2554                 if (r_shadow_bouncegridtexture)
2555                 {
2556                         R_FreeTexture(r_shadow_bouncegridtexture);
2557                         r_shadow_bouncegridtexture = NULL;
2558                 }
2559                 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2560                 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2561         }
2562         r_shadow_bouncegridnumpixels = numpixels;
2563         pixels = r_shadow_bouncegridpixels;
2564         highpixels = r_shadow_bouncegridhighpixels;
2565         if (settings.directionalshading)
2566                 memset(pixels, 128, numpixels * sizeof(unsigned char[4]));
2567         else
2568                 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2569         memset(highpixels, 0, numpixels * sizeof(float[4]));
2570         // figure out what we want to interact with
2571         if (settings.hitmodels)
2572                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2573         else
2574                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2575         maxbounce = settings.maxbounce;
2576         // clear variables that produce warnings otherwise
2577         memset(splatcolor, 0, sizeof(splatcolor));
2578         // iterate world rtlights
2579         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2580         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2581         range2 = range + range1;
2582         photoncount = 0;
2583         for (lightindex = 0;lightindex < range2;lightindex++)
2584         {
2585                 if (settings.staticmode)
2586                 {
2587                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2588                         if (!light || !(light->flags & flag))
2589                                 continue;
2590                         rtlight = &light->rtlight;
2591                         // when static, we skip styled lights because they tend to change...
2592                         if (rtlight->style > 0)
2593                                 continue;
2594                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2595                 }
2596                 else
2597                 {
2598                         if (lightindex < range)
2599                         {
2600                                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2601                                 rtlight = &light->rtlight;
2602                         }
2603                         else
2604                                 rtlight = r_refdef.scene.lights[lightindex - range];
2605                         // draw only visible lights (major speedup)
2606                         if (!rtlight->draw)
2607                                 continue;
2608                         VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2609                 }
2610                 if (!VectorLength2(lightcolor))
2611                         continue;
2612                 // shoot particles from this light
2613                 // use a calculation for the number of particles that will not
2614                 // vary with lightstyle, otherwise we get randomized particle
2615                 // distribution, the seeded random is only consistent for a
2616                 // consistent number of particles on this light...
2617                 radius = rtlight->radius * settings.lightradiusscale;
2618                 s = rtlight->radius;
2619                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2620                 if (lightindex >= range)
2621                         lightintensity *= settings.dlightparticlemultiplier;
2622                 photoncount += max(0.0f, lightintensity * s * s);
2623         }
2624         photonscaling = (float)settings.photons / max(1, photoncount);
2625         photonresidual = 0.0f;
2626         for (lightindex = 0;lightindex < range2;lightindex++)
2627         {
2628                 if (settings.staticmode)
2629                 {
2630                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2631                         if (!light || !(light->flags & flag))
2632                                 continue;
2633                         rtlight = &light->rtlight;
2634                         // when static, we skip styled lights because they tend to change...
2635                         if (rtlight->style > 0)
2636                                 continue;
2637                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2638                 }
2639                 else
2640                 {
2641                         if (lightindex < range)
2642                         {
2643                                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2644                                 rtlight = &light->rtlight;
2645                         }
2646                         else
2647                                 rtlight = r_refdef.scene.lights[lightindex - range];
2648                         // draw only visible lights (major speedup)
2649                         if (!rtlight->draw)
2650                                 continue;
2651                         VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2652                 }
2653                 if (!VectorLength2(lightcolor))
2654                         continue;
2655                 // shoot particles from this light
2656                 // use a calculation for the number of particles that will not
2657                 // vary with lightstyle, otherwise we get randomized particle
2658                 // distribution, the seeded random is only consistent for a
2659                 // consistent number of particles on this light...
2660                 radius = rtlight->radius * settings.lightradiusscale;
2661                 s = rtlight->radius;
2662                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2663                 if (lightindex >= range)
2664                         lightintensity *= settings.dlightparticlemultiplier;
2665                 photonresidual += lightintensity * s * s * photonscaling;
2666                 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2667                 if (!shootparticles)
2668                         continue;
2669                 photonresidual -= shootparticles;
2670                 s = settings.particleintensity / shootparticles;
2671                 VectorScale(lightcolor, s, baseshotcolor);
2672                 if (VectorLength2(baseshotcolor) == 0.0f)
2673                         break;
2674                 r_refdef.stats.bouncegrid_lights++;
2675                 r_refdef.stats.bouncegrid_particles += shootparticles;
2676                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2677                 {
2678                         if (settings.stablerandom > 0)
2679                                 seed = lightindex * 11937 + shotparticles;
2680                         VectorCopy(baseshotcolor, shotcolor);
2681                         VectorCopy(rtlight->shadoworigin, clipstart);
2682                         if (settings.stablerandom < 0)
2683                                 VectorRandom(clipend);
2684                         else
2685                                 VectorCheeseRandom(clipend);
2686                         VectorMA(clipstart, radius, clipend, clipend);
2687                         for (bouncecount = 0;;bouncecount++)
2688                         {
2689                                 r_refdef.stats.bouncegrid_traces++;
2690                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2691                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2692                                 if (settings.staticmode)
2693                                         Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, true);
2694                                 else
2695                                         cliptrace = CL_TraceLine(clipstart, clipend, settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
2696                                 if (cliptrace.fraction >= 1.0f)
2697                                         break;
2698                                 r_refdef.stats.bouncegrid_hits++;
2699                                 if (bouncecount > 0)
2700                                 {
2701                                         r_refdef.stats.bouncegrid_splats++;
2702                                         // figure out which texture pixel this is in
2703                                         texlerp[1][0] = ((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2704                                         texlerp[1][1] = ((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2705                                         texlerp[1][2] = ((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2706                                         tex[0] = (int)floor(texlerp[1][0]);
2707                                         tex[1] = (int)floor(texlerp[1][1]);
2708                                         tex[2] = (int)floor(texlerp[1][2]);
2709                                         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)
2710                                         {
2711                                                 // it is within bounds...  do the real work now
2712                                                 // calculate first order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2713                                                 if (settings.directionalshading)
2714                                                 {
2715                                                         VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2716                                                         VectorNormalize(clipdiff);
2717                                                         splatcolor[ 0] = shotcolor[0] * clipdiff[2];
2718                                                         splatcolor[ 1] = shotcolor[0] * clipdiff[1];
2719                                                         splatcolor[ 2] = shotcolor[0] * clipdiff[0];
2720                                                         splatcolor[ 3] = shotcolor[0];
2721                                                         splatcolor[ 4] = shotcolor[1] * clipdiff[2];
2722                                                         splatcolor[ 5] = shotcolor[1] * clipdiff[1];
2723                                                         splatcolor[ 6] = shotcolor[1] * clipdiff[0];
2724                                                         splatcolor[ 7] = shotcolor[1];
2725                                                         splatcolor[ 8] = shotcolor[2] * clipdiff[2];
2726                                                         splatcolor[ 9] = shotcolor[2] * clipdiff[1];
2727                                                         splatcolor[10] = shotcolor[2] * clipdiff[0];
2728                                                         splatcolor[11] = shotcolor[2];
2729                                                         w = VectorLength(shotcolor);
2730                                                         splatcolor[12] = clipdiff[2] * w;
2731                                                         splatcolor[13] = clipdiff[1] * w;
2732                                                         splatcolor[14] = clipdiff[0] * w;
2733                                                         splatcolor[15] = 1.0f;
2734                                                 }
2735                                                 else
2736                                                 {
2737                                                         splatcolor[ 0] = shotcolor[2];
2738                                                         splatcolor[ 1] = shotcolor[1];
2739                                                         splatcolor[ 2] = shotcolor[0];
2740                                                         splatcolor[ 3] = 1.0f;
2741                                                 }
2742                                                 // calculate the lerp factors
2743                                                 texlerp[1][0] -= tex[0];
2744                                                 texlerp[1][1] -= tex[1];
2745                                                 texlerp[1][2] -= tex[2];
2746                                                 texlerp[0][0] = 1.0f - texlerp[1][0];
2747                                                 texlerp[0][1] = 1.0f - texlerp[1][1];
2748                                                 texlerp[0][2] = 1.0f - texlerp[1][2];
2749                                                 // calculate individual pixel indexes and weights
2750                                                 pixelindex[0] = (((tex[2]  )*resolution[1]+tex[1]  )*resolution[0]+tex[0]  );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2751                                                 pixelindex[1] = (((tex[2]  )*resolution[1]+tex[1]  )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2752                                                 pixelindex[2] = (((tex[2]  )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]  );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2753                                                 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]);
2754                                                 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1]  )*resolution[0]+tex[0]  );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2755                                                 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]);
2756                                                 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]);
2757                                                 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]);
2758                                                 // update the 8 pixels...
2759                                                 for (corner = 0;corner < 8;corner++)
2760                                                 {
2761                                                         // calculate address for first set of coefficients
2762                                                         w = pixelweight[corner];
2763                                                         pixel = pixels + 4 * pixelindex[corner];
2764                                                         highpixel = highpixels + 4 * pixelindex[corner];
2765                                                         // add to the high precision pixel color
2766                                                         highpixel[0] += (splatcolor[ 0]*w);
2767                                                         highpixel[1] += (splatcolor[ 1]*w);
2768                                                         highpixel[2] += (splatcolor[ 2]*w);
2769                                                         highpixel[3] += (splatcolor[ 3]*w);
2770                                                         // flag the low precision pixel as needing to be updated
2771                                                         pixel[3] = 255;
2772                                                         if (settings.directionalshading)
2773                                                         {
2774                                                                 // advance to second set of coefficients
2775                                                                 pixel += numpixels;
2776                                                                 highpixel += numpixels;
2777                                                                 // add to the high precision pixel color
2778                                                                 highpixel[0] += (splatcolor[ 4]*w);
2779                                                                 highpixel[1] += (splatcolor[ 5]*w);
2780                                                                 highpixel[2] += (splatcolor[ 6]*w);
2781                                                                 highpixel[3] += (splatcolor[ 7]*w);
2782                                                                 // flag the low precision pixel as needing to be updated
2783                                                                 pixel[3] = 255;
2784                                                                 // advance to third set of coefficients
2785                                                                 pixel += numpixels;
2786                                                                 highpixel += numpixels;
2787                                                                 // add to the high precision pixel color
2788                                                                 highpixel[0] += (splatcolor[ 8]*w);
2789                                                                 highpixel[1] += (splatcolor[ 9]*w);
2790                                                                 highpixel[2] += (splatcolor[10]*w);
2791                                                                 highpixel[3] += (splatcolor[11]*w);
2792                                                                 // flag the low precision pixel as needing to be updated
2793                                                                 pixel[3] = 255;
2794                                                                 // advance to fourth set of coefficients
2795                                                                 pixel += numpixels;
2796                                                                 highpixel += numpixels;
2797                                                                 // add to the high precision pixel color
2798                                                                 highpixel[0] += (splatcolor[12]*w);
2799                                                                 highpixel[1] += (splatcolor[13]*w);
2800                                                                 highpixel[2] += (splatcolor[14]*w);
2801                                                                 highpixel[3] += (splatcolor[15]*w);
2802                                                                 // flag the low precision pixel as needing to be updated
2803                                                                 pixel[3] = 255;
2804                                                         }
2805                                                 }
2806                                         }
2807                                 }
2808                                 if (bouncecount >= maxbounce)
2809                                         break;
2810                                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2811                                 // also clamp the resulting color to never add energy, even if the user requests extreme values
2812                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2813                                         VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2814                                 else
2815                                         VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2816                                 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2817                                 surfcolor[0] = min(surfcolor[0], 1.0f);
2818                                 surfcolor[1] = min(surfcolor[1], 1.0f);
2819                                 surfcolor[2] = min(surfcolor[2], 1.0f);
2820                                 VectorMultiply(shotcolor, surfcolor, shotcolor);
2821                                 if (VectorLength2(baseshotcolor) == 0.0f)
2822                                         break;
2823                                 r_refdef.stats.bouncegrid_bounces++;
2824                                 if (settings.bounceanglediffuse)
2825                                 {
2826                                         // random direction, primarily along plane normal
2827                                         s = VectorDistance(cliptrace.endpos, clipend);
2828                                         if (settings.stablerandom < 0)
2829                                                 VectorRandom(clipend);
2830                                         else
2831                                                 VectorCheeseRandom(clipend);
2832                                         VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2833                                         VectorNormalize(clipend);
2834                                         VectorScale(clipend, s, clipend);
2835                                 }
2836                                 else
2837                                 {
2838                                         // reflect the remaining portion of the line across plane normal
2839                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2840                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2841                                 }
2842                                 // calculate the new line start and end
2843                                 VectorCopy(cliptrace.endpos, clipstart);
2844                                 VectorAdd(clipstart, clipend, clipend);
2845                         }
2846                 }
2847         }
2848         // generate pixels array from highpixels array
2849         // skip first and last columns, rows, and layers as these are blank
2850         // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2851         for (d = 0;d < 4;d++)
2852         {
2853                 for (z = 1;z < resolution[2]-1;z++)
2854                 {
2855                         for (y = 1;y < resolution[1]-1;y++)
2856                         {
2857                                 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)
2858                                 {
2859                                         // only convert pixels that were hit by photons
2860                                         if (pixel[3] == 255)
2861                                         {
2862                                                 // normalize the bentnormal...
2863                                                 if (settings.directionalshading)
2864                                                 {
2865                                                         if (d == 3)
2866                                                                 VectorNormalize(highpixel);
2867                                                         c[0] = (int)(highpixel[0]*128.0f+128.0f);
2868                                                         c[1] = (int)(highpixel[1]*128.0f+128.0f);
2869                                                         c[2] = (int)(highpixel[2]*128.0f+128.0f);
2870                                                         c[3] = (int)(highpixel[3]*128.0f+128.0f);
2871                                                 }
2872                                                 else
2873                                                 {
2874                                                         c[0] = (int)(highpixel[0]*256.0f);
2875                                                         c[1] = (int)(highpixel[1]*256.0f);
2876                                                         c[2] = (int)(highpixel[2]*256.0f);
2877                                                         c[3] = (int)(highpixel[3]*256.0f);
2878                                                 }
2879                                                 pixel[0] = (unsigned char)bound(0, c[0], 255);
2880                                                 pixel[1] = (unsigned char)bound(0, c[1], 255);
2881                                                 pixel[2] = (unsigned char)bound(0, c[2], 255);
2882                                                 pixel[3] = (unsigned char)bound(0, c[3], 255);
2883                                         }
2884                                 }
2885                         }
2886                 }
2887                 if (!settings.directionalshading)
2888                         break;
2889         }
2890         if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2891                 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*(settings.directionalshading ? 4 : 1));
2892         else
2893         {
2894                 VectorCopy(resolution, r_shadow_bouncegridresolution);
2895                 if (r_shadow_bouncegridtexture)
2896                         R_FreeTexture(r_shadow_bouncegridtexture);
2897                 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);
2898         }
2899         r_shadow_bouncegridtime = realtime;
2900 }
2901
2902 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2903 {
2904         R_Shadow_RenderMode_Reset();
2905         GL_BlendFunc(GL_ONE, GL_ONE);
2906         GL_DepthRange(0, 1);
2907         GL_DepthTest(r_showshadowvolumes.integer < 2);
2908         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2909         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2910         GL_CullFace(GL_NONE);
2911         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2912 }
2913
2914 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2915 {
2916         R_Shadow_RenderMode_Reset();
2917         GL_BlendFunc(GL_ONE, GL_ONE);
2918         GL_DepthRange(0, 1);
2919         GL_DepthTest(r_showlighting.integer < 2);
2920         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2921         if (!transparent)
2922                 GL_DepthFunc(GL_EQUAL);
2923         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2924         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2925 }
2926
2927 void R_Shadow_RenderMode_End(void)
2928 {
2929         R_Shadow_RenderMode_Reset();
2930         R_Shadow_RenderMode_ActiveLight(NULL);
2931         GL_DepthMask(true);
2932         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2933         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2934 }
2935
2936 int bboxedges[12][2] =
2937 {
2938         // top
2939         {0, 1}, // +X
2940         {0, 2}, // +Y
2941         {1, 3}, // Y, +X
2942         {2, 3}, // X, +Y
2943         // bottom
2944         {4, 5}, // +X
2945         {4, 6}, // +Y
2946         {5, 7}, // Y, +X
2947         {6, 7}, // X, +Y
2948         // verticals
2949         {0, 4}, // +Z
2950         {1, 5}, // X, +Z
2951         {2, 6}, // Y, +Z
2952         {3, 7}, // XY, +Z
2953 };
2954
2955 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2956 {
2957         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass)
2958         {
2959                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2960                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2961                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2962                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2963                 return false;
2964         }
2965         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2966                 return true; // invisible
2967         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2968         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2969         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2970         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2971                 r_refdef.stats.lights_scissored++;
2972         return false;
2973 }
2974
2975 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2976 {
2977         int i;
2978         const float *vertex3f;
2979         const float *normal3f;
2980         float *color4f;
2981         float dist, dot, distintensity, shadeintensity, v[3], n[3];
2982         switch (r_shadow_rendermode)
2983         {
2984         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2985         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2986                 if (VectorLength2(diffusecolor) > 0)
2987                 {
2988                         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)
2989                         {
2990                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2991                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2992                                 if ((dot = DotProduct(n, v)) < 0)
2993                                 {
2994                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2995                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2996                                 }
2997                                 else
2998                                         VectorCopy(ambientcolor, color4f);
2999                                 if (r_refdef.fogenabled)
3000                                 {
3001                                         float f;
3002                                         f = RSurf_FogVertex(vertex3f);
3003                                         VectorScale(color4f, f, color4f);
3004                                 }
3005                                 color4f[3] = 1;
3006                         }
3007                 }
3008                 else
3009                 {
3010                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3011                         {
3012                                 VectorCopy(ambientcolor, color4f);
3013                                 if (r_refdef.fogenabled)
3014                                 {
3015                                         float f;
3016                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3017                                         f = RSurf_FogVertex(vertex3f);
3018                                         VectorScale(color4f + 4*i, f, color4f);
3019                                 }
3020                                 color4f[3] = 1;
3021                         }
3022                 }
3023                 break;
3024         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3025                 if (VectorLength2(diffusecolor) > 0)
3026                 {
3027                         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)
3028                         {
3029                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3030                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3031                                 {
3032                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3033                                         if ((dot = DotProduct(n, v)) < 0)
3034                                         {
3035                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3036                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3037                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3038                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3039                                         }
3040                                         else
3041                                         {
3042                                                 color4f[0] = ambientcolor[0] * distintensity;
3043                                                 color4f[1] = ambientcolor[1] * distintensity;
3044                                                 color4f[2] = ambientcolor[2] * distintensity;
3045                                         }
3046                                         if (r_refdef.fogenabled)
3047                                         {
3048                                                 float f;
3049                                                 f = RSurf_FogVertex(vertex3f);
3050                                                 VectorScale(color4f, f, color4f);
3051                                         }
3052                                 }
3053                                 else
3054                                         VectorClear(color4f);
3055                                 color4f[3] = 1;
3056                         }
3057                 }
3058                 else
3059                 {
3060                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3061                         {
3062                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3063                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3064                                 {
3065                                         color4f[0] = ambientcolor[0] * distintensity;
3066                                         color4f[1] = ambientcolor[1] * distintensity;
3067                                         color4f[2] = ambientcolor[2] * distintensity;
3068                                         if (r_refdef.fogenabled)
3069                                         {
3070                                                 float f;
3071                                                 f = RSurf_FogVertex(vertex3f);
3072                                                 VectorScale(color4f, f, color4f);
3073                                         }
3074                                 }
3075                                 else
3076                                         VectorClear(color4f);
3077                                 color4f[3] = 1;
3078                         }
3079                 }
3080                 break;
3081         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3082                 if (VectorLength2(diffusecolor) > 0)
3083                 {
3084                         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)
3085                         {
3086                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3087                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3088                                 {
3089                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3090                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3091                                         if ((dot = DotProduct(n, v)) < 0)
3092                                         {
3093                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3094                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3095                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3096                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3097                                         }
3098                                         else
3099                                         {
3100                                                 color4f[0] = ambientcolor[0] * distintensity;
3101                                                 color4f[1] = ambientcolor[1] * distintensity;
3102                                                 color4f[2] = ambientcolor[2] * distintensity;
3103                                         }
3104                                         if (r_refdef.fogenabled)
3105                                         {
3106                                                 float f;
3107                                                 f = RSurf_FogVertex(vertex3f);
3108                                                 VectorScale(color4f, f, color4f);
3109                                         }
3110                                 }
3111                                 else
3112                                         VectorClear(color4f);
3113                                 color4f[3] = 1;
3114                         }
3115                 }
3116                 else
3117                 {
3118                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3119                         {
3120                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3121                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3122                                 {
3123                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3124                                         color4f[0] = ambientcolor[0] * distintensity;
3125                                         color4f[1] = ambientcolor[1] * distintensity;
3126                                         color4f[2] = ambientcolor[2] * distintensity;
3127                                         if (r_refdef.fogenabled)
3128                                         {
3129                                                 float f;
3130                                                 f = RSurf_FogVertex(vertex3f);
3131                                                 VectorScale(color4f, f, color4f);
3132                                         }
3133                                 }
3134                                 else
3135                                         VectorClear(color4f);
3136                                 color4f[3] = 1;
3137                         }
3138                 }
3139                 break;
3140         default:
3141                 break;
3142         }
3143 }
3144
3145 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3146 {
3147         // used to display how many times a surface is lit for level design purposes
3148         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3149         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3150         RSurf_DrawBatch();
3151 }
3152
3153 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3154 {
3155         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3156         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3157         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3158                 GL_DepthFunc(GL_EQUAL);
3159         RSurf_DrawBatch();
3160         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3161                 GL_DepthFunc(GL_LEQUAL);
3162 }
3163
3164 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3165 {
3166         int renders;
3167         int i;
3168         int stop;
3169         int newfirstvertex;
3170         int newlastvertex;
3171         int newnumtriangles;
3172         int *newe;
3173         const int *e;
3174         float *c;
3175         int maxtriangles = 4096;
3176         static int newelements[4096*3];
3177         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3178         for (renders = 0;renders < 4;renders++)
3179         {
3180                 stop = true;
3181                 newfirstvertex = 0;
3182                 newlastvertex = 0;
3183                 newnumtriangles = 0;
3184                 newe = newelements;
3185                 // due to low fillrate on the cards this vertex lighting path is
3186                 // designed for, we manually cull all triangles that do not
3187                 // contain a lit vertex
3188                 // this builds batches of triangles from multiple surfaces and
3189                 // renders them at once
3190                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3191                 {
3192                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3193                         {
3194                                 if (newnumtriangles)
3195                                 {
3196                                         newfirstvertex = min(newfirstvertex, e[0]);
3197                                         newlastvertex  = max(newlastvertex, e[0]);
3198                                 }
3199                                 else
3200                                 {
3201                                         newfirstvertex = e[0];
3202                                         newlastvertex = e[0];
3203                                 }
3204                                 newfirstvertex = min(newfirstvertex, e[1]);
3205                                 newlastvertex  = max(newlastvertex, e[1]);
3206                                 newfirstvertex = min(newfirstvertex, e[2]);
3207                                 newlastvertex  = max(newlastvertex, e[2]);
3208                                 newe[0] = e[0];
3209                                 newe[1] = e[1];
3210                                 newe[2] = e[2];
3211                                 newnumtriangles++;
3212                                 newe += 3;
3213                                 if (newnumtriangles >= maxtriangles)
3214                                 {
3215                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3216                                         newnumtriangles = 0;
3217                                         newe = newelements;
3218                                         stop = false;
3219                                 }
3220                         }
3221                 }
3222                 if (newnumtriangles >= 1)
3223                 {
3224                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3225                         stop = false;
3226                 }
3227                 // if we couldn't find any lit triangles, exit early
3228                 if (stop)
3229                         break;
3230                 // now reduce the intensity for the next overbright pass
3231                 // we have to clamp to 0 here incase the drivers have improper
3232                 // handling of negative colors
3233                 // (some old drivers even have improper handling of >1 color)
3234                 stop = true;
3235                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3236                 {
3237                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3238                         {
3239                                 c[0] = max(0, c[0] - 1);
3240                                 c[1] = max(0, c[1] - 1);
3241                                 c[2] = max(0, c[2] - 1);
3242                                 stop = false;
3243                         }
3244                         else
3245                                 VectorClear(c);
3246                 }
3247                 // another check...
3248                 if (stop)
3249                         break;
3250         }
3251 }
3252
3253 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3254 {
3255         // OpenGL 1.1 path (anything)
3256         float ambientcolorbase[3], diffusecolorbase[3];
3257         float ambientcolorpants[3], diffusecolorpants[3];
3258         float ambientcolorshirt[3], diffusecolorshirt[3];
3259         const float *surfacecolor = rsurface.texture->dlightcolor;
3260         const float *surfacepants = rsurface.colormap_pantscolor;
3261         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3262         rtexture_t *basetexture = rsurface.texture->basetexture;
3263         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3264         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3265         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3266         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3267         ambientscale *= 2 * r_refdef.view.colorscale;
3268         diffusescale *= 2 * r_refdef.view.colorscale;
3269         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3270         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3271         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3272         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3273         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3274         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3275         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3276         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3277         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3278         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3279         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3280         R_Mesh_TexBind(0, basetexture);
3281         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3282         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3283         switch(r_shadow_rendermode)
3284         {
3285         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3286                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3287                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3288                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3289                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3290                 break;
3291         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3292                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3293                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3294                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3295                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3296                 // fall through
3297         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3298                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3299                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3300                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3301                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3302                 break;
3303         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3304                 break;
3305         default:
3306                 break;
3307         }
3308         //R_Mesh_TexBind(0, basetexture);
3309         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3310         if (dopants)
3311         {
3312                 R_Mesh_TexBind(0, pantstexture);
3313                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3314         }
3315         if (doshirt)
3316         {
3317                 R_Mesh_TexBind(0, shirttexture);
3318                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3319         }
3320 }
3321
3322 extern cvar_t gl_lightmaps;
3323 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3324 {
3325         float ambientscale, diffusescale, specularscale;
3326         qboolean negated;
3327         float lightcolor[3];
3328         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3329         ambientscale = rsurface.rtlight->ambientscale;
3330         diffusescale = rsurface.rtlight->diffusescale;
3331         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3332         if (!r_shadow_usenormalmap.integer)
3333         {
3334                 ambientscale += 1.0f * diffusescale;
3335                 diffusescale = 0;
3336                 specularscale = 0;
3337         }
3338         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3339                 return;
3340         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3341         if(negated)
3342         {
3343                 VectorNegate(lightcolor, lightcolor);
3344                 switch(vid.renderpath)
3345                 {
3346                 case RENDERPATH_GL11:
3347                 case RENDERPATH_GL13:
3348                 case RENDERPATH_GL20:
3349                 case RENDERPATH_GLES2:
3350                         qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3351                         break;
3352                 case RENDERPATH_D3D9:
3353 #ifdef SUPPORTD3D
3354                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3355 #endif
3356                         break;
3357                 case RENDERPATH_D3D10:
3358                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3359                         break;
3360                 case RENDERPATH_D3D11:
3361                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3362                         break;
3363                 case RENDERPATH_SOFT:
3364                         DPSOFTRAST_BlendSubtract(true);
3365                         break;
3366                 }
3367         }
3368         RSurf_SetupDepthAndCulling();
3369         switch (r_shadow_rendermode)
3370         {
3371         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3372                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3373                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3374                 break;
3375         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3376                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3377                 break;
3378         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3379         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3380         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3381         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3382                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3383                 break;
3384         default:
3385                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3386                 break;
3387         }
3388         if(negated)
3389         {
3390                 switch(vid.renderpath)
3391                 {
3392                 case RENDERPATH_GL11:
3393                 case RENDERPATH_GL13:
3394                 case RENDERPATH_GL20:
3395                 case RENDERPATH_GLES2:
3396                         qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3397                         break;
3398                 case RENDERPATH_D3D9:
3399 #ifdef SUPPORTD3D
3400                         IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3401 #endif
3402                         break;
3403                 case RENDERPATH_D3D10:
3404                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3405                         break;
3406                 case RENDERPATH_D3D11:
3407                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3408                         break;
3409                 case RENDERPATH_SOFT:
3410                         DPSOFTRAST_BlendSubtract(false);
3411                         break;
3412                 }
3413         }
3414 }
3415
3416 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)
3417 {
3418         matrix4x4_t tempmatrix = *matrix;
3419         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3420
3421         // if this light has been compiled before, free the associated data
3422         R_RTLight_Uncompile(rtlight);
3423
3424         // clear it completely to avoid any lingering data
3425         memset(rtlight, 0, sizeof(*rtlight));
3426
3427         // copy the properties
3428         rtlight->matrix_lighttoworld = tempmatrix;
3429         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3430         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3431         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3432         VectorCopy(color, rtlight->color);
3433         rtlight->cubemapname[0] = 0;
3434         if (cubemapname && cubemapname[0])
3435                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3436         rtlight->shadow = shadow;
3437         rtlight->corona = corona;
3438         rtlight->style = style;
3439         rtlight->isstatic = isstatic;
3440         rtlight->coronasizescale = coronasizescale;
3441         rtlight->ambientscale = ambientscale;
3442         rtlight->diffusescale = diffusescale;
3443         rtlight->specularscale = specularscale;
3444         rtlight->flags = flags;
3445
3446         // compute derived data
3447         //rtlight->cullradius = rtlight->radius;
3448         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3449         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3450         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3451         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3452         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3453         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3454         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3455 }
3456
3457 // compiles rtlight geometry
3458 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3459 void R_RTLight_Compile(rtlight_t *rtlight)
3460 {
3461         int i;
3462         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3463         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3464         entity_render_t *ent = r_refdef.scene.worldentity;
3465         dp_model_t *model = r_refdef.scene.worldmodel;
3466         unsigned char *data;
3467         shadowmesh_t *mesh;
3468
3469         // compile the light
3470         rtlight->compiled = true;
3471         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3472         rtlight->static_numleafs = 0;
3473         rtlight->static_numleafpvsbytes = 0;
3474         rtlight->static_leaflist = NULL;
3475         rtlight->static_leafpvs = NULL;
3476         rtlight->static_numsurfaces = 0;
3477         rtlight->static_surfacelist = NULL;
3478         rtlight->static_shadowmap_receivers = 0x3F;
3479         rtlight->static_shadowmap_casters = 0x3F;
3480         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3481         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3482         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3483         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3484         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3485         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3486
3487         if (model && model->GetLightInfo)
3488         {
3489                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3490                 r_shadow_compilingrtlight = rtlight;
3491                 R_FrameData_SetMark();
3492                 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);
3493                 R_FrameData_ReturnToMark();
3494                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3495                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3496                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3497                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3498                 rtlight->static_numsurfaces = numsurfaces;
3499                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3500                 rtlight->static_numleafs = numleafs;
3501                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3502                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3503                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3504                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3505                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3506                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3507                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3508                 if (rtlight->static_numsurfaces)
3509                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3510                 if (rtlight->static_numleafs)
3511                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3512                 if (rtlight->static_numleafpvsbytes)
3513                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3514                 if (rtlight->static_numshadowtrispvsbytes)
3515                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3516                 if (rtlight->static_numlighttrispvsbytes)
3517                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3518                 R_FrameData_SetMark();
3519                 switch (rtlight->shadowmode)
3520                 {
3521                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3522                         if (model->CompileShadowMap && rtlight->shadow)
3523                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3524                         break;
3525                 default:
3526                         if (model->CompileShadowVolume && rtlight->shadow)
3527                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3528                         break;
3529                 }
3530                 R_FrameData_ReturnToMark();
3531                 // now we're done compiling the rtlight
3532                 r_shadow_compilingrtlight = NULL;
3533         }
3534
3535
3536         // use smallest available cullradius - box radius or light radius
3537         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3538         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3539
3540         shadowzpasstris = 0;
3541         if (rtlight->static_meshchain_shadow_zpass)
3542                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3543                         shadowzpasstris += mesh->numtriangles;
3544
3545         shadowzfailtris = 0;
3546         if (rtlight->static_meshchain_shadow_zfail)
3547                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3548                         shadowzfailtris += mesh->numtriangles;
3549
3550         lighttris = 0;
3551         if (rtlight->static_numlighttrispvsbytes)
3552                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3553                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3554                                 lighttris++;
3555
3556         shadowtris = 0;
3557         if (rtlight->static_numlighttrispvsbytes)
3558                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3559                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3560                                 shadowtris++;
3561
3562         if (developer_extra.integer)
3563                 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);
3564 }
3565
3566 void R_RTLight_Uncompile(rtlight_t *rtlight)
3567 {
3568         if (rtlight->compiled)
3569         {
3570                 if (rtlight->static_meshchain_shadow_zpass)
3571                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3572                 rtlight->static_meshchain_shadow_zpass = NULL;
3573                 if (rtlight->static_meshchain_shadow_zfail)
3574                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3575                 rtlight->static_meshchain_shadow_zfail = NULL;
3576                 if (rtlight->static_meshchain_shadow_shadowmap)
3577                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3578                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3579                 // these allocations are grouped
3580                 if (rtlight->static_surfacelist)
3581                         Mem_Free(rtlight->static_surfacelist);
3582                 rtlight->static_numleafs = 0;
3583                 rtlight->static_numleafpvsbytes = 0;
3584                 rtlight->static_leaflist = NULL;
3585                 rtlight->static_leafpvs = NULL;
3586                 rtlight->static_numsurfaces = 0;
3587                 rtlight->static_surfacelist = NULL;
3588                 rtlight->static_numshadowtrispvsbytes = 0;
3589                 rtlight->static_shadowtrispvs = NULL;
3590                 rtlight->static_numlighttrispvsbytes = 0;
3591                 rtlight->static_lighttrispvs = NULL;
3592                 rtlight->compiled = false;
3593         }
3594 }
3595
3596 void R_Shadow_UncompileWorldLights(void)
3597 {
3598         size_t lightindex;
3599         dlight_t *light;
3600         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3601         for (lightindex = 0;lightindex < range;lightindex++)
3602         {
3603                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3604                 if (!light)
3605                         continue;
3606                 R_RTLight_Uncompile(&light->rtlight);
3607         }
3608 }
3609
3610 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3611 {
3612         int i, j;
3613         mplane_t plane;
3614         // reset the count of frustum planes
3615         // see rtlight->cached_frustumplanes definition for how much this array
3616         // can hold
3617         rtlight->cached_numfrustumplanes = 0;
3618
3619         // haven't implemented a culling path for ortho rendering
3620         if (!r_refdef.view.useperspective)
3621         {
3622                 // check if the light is on screen and copy the 4 planes if it is
3623                 for (i = 0;i < 4;i++)
3624                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3625                                 break;
3626                 if (i == 4)
3627                         for (i = 0;i < 4;i++)
3628                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3629                 return;
3630         }
3631
3632 #if 1
3633         // generate a deformed frustum that includes the light origin, this is
3634         // used to cull shadow casting surfaces that can not possibly cast a
3635         // shadow onto the visible light-receiving surfaces, which can be a
3636         // performance gain
3637         //
3638         // if the light origin is onscreen the result will be 4 planes exactly
3639         // if the light origin is offscreen on only one axis the result will
3640         // be exactly 5 planes (split-side case)
3641         // if the light origin is offscreen on two axes the result will be
3642         // exactly 4 planes (stretched corner case)
3643         for (i = 0;i < 4;i++)
3644         {
3645                 // quickly reject standard frustum planes that put the light
3646                 // origin outside the frustum
3647                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3648                         continue;
3649                 // copy the plane
3650                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3651         }
3652         // if all the standard frustum planes were accepted, the light is onscreen
3653         // otherwise we need to generate some more planes below...
3654         if (rtlight->cached_numfrustumplanes < 4)
3655         {
3656                 // at least one of the stock frustum planes failed, so we need to
3657                 // create one or two custom planes to enclose the light origin
3658                 for (i = 0;i < 4;i++)
3659                 {
3660                         // create a plane using the view origin and light origin, and a
3661                         // single point from the frustum corner set
3662                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3663                         VectorNormalize(plane.normal);
3664                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3665                         // see if this plane is backwards and flip it if so
3666                         for (j = 0;j < 4;j++)
3667                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3668                                         break;
3669                         if (j < 4)
3670                         {
3671                                 VectorNegate(plane.normal, plane.normal);
3672                                 plane.dist *= -1;
3673                                 // flipped plane, test again to see if it is now valid
3674                                 for (j = 0;j < 4;j++)
3675                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3676                                                 break;
3677                                 // if the plane is still not valid, then it is dividing the
3678                                 // frustum and has to be rejected
3679                                 if (j < 4)
3680                                         continue;
3681                         }
3682                         // we have created a valid plane, compute extra info
3683                         PlaneClassify(&plane);
3684                         // copy the plane
3685                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3686 #if 1
3687                         // if we've found 5 frustum planes then we have constructed a
3688                         // proper split-side case and do not need to keep searching for
3689                         // planes to enclose the light origin
3690                         if (rtlight->cached_numfrustumplanes == 5)
3691                                 break;
3692 #endif
3693                 }
3694         }
3695 #endif
3696
3697 #if 0
3698         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3699         {
3700                 plane = rtlight->cached_frustumplanes[i];
3701                 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));
3702         }
3703 #endif
3704
3705 #if 0
3706         // now add the light-space box planes if the light box is rotated, as any
3707         // caster outside the oriented light box is irrelevant (even if it passed
3708         // the worldspace light box, which is axial)
3709         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3710         {
3711                 for (i = 0;i < 6;i++)
3712                 {
3713                         vec3_t v;
3714                         VectorClear(v);
3715                         v[i >> 1] = (i & 1) ? -1 : 1;
3716                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3717                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3718                         plane.dist = VectorNormalizeLength(plane.normal);
3719                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3720                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3721                 }
3722         }
3723 #endif
3724
3725 #if 0
3726         // add the world-space reduced box planes
3727         for (i = 0;i < 6;i++)
3728         {
3729                 VectorClear(plane.normal);
3730                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3731                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3732                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3733         }
3734 #endif
3735
3736 #if 0
3737         {
3738         int j, oldnum;
3739         vec3_t points[8];
3740         vec_t bestdist;
3741         // reduce all plane distances to tightly fit the rtlight cull box, which
3742         // is in worldspace
3743         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3744         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3745         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3746         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3747         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3748         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3749         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3750         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3751         oldnum = rtlight->cached_numfrustumplanes;
3752         rtlight->cached_numfrustumplanes = 0;
3753         for (j = 0;j < oldnum;j++)
3754         {
3755                 // find the nearest point on the box to this plane
3756                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3757                 for (i = 1;i < 8;i++)
3758                 {
3759                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3760                         if (bestdist > dist)
3761                                 bestdist = dist;
3762                 }
3763                 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);
3764                 // if the nearest point is near or behind the plane, we want this
3765                 // plane, otherwise the plane is useless as it won't cull anything
3766                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3767                 {
3768                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3769                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3770                 }
3771         }
3772         }
3773 #endif
3774 }
3775
3776 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3777 {
3778         shadowmesh_t *mesh;
3779
3780         RSurf_ActiveWorldEntity();
3781
3782         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3783         {
3784                 CHECKGLERROR
3785                 GL_CullFace(GL_NONE);
3786                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3787                 for (;mesh;mesh = mesh->next)
3788                 {
3789                         if (!mesh->sidetotals[r_shadow_shadowmapside])
3790                                 continue;
3791                         r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3792                         if (mesh->vertex3fbuffer)
3793                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3794                         else
3795                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3796                         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);
3797                 }
3798                 CHECKGLERROR
3799         }
3800         else if (r_refdef.scene.worldentity->model)
3801                 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);
3802
3803         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3804 }
3805
3806 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3807 {
3808         qboolean zpass = false;
3809         shadowmesh_t *mesh;
3810         int t, tend;
3811         int surfacelistindex;
3812         msurface_t *surface;
3813
3814         // if triangle neighbors are disabled, shadowvolumes are disabled
3815         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3816                 return;
3817
3818         RSurf_ActiveWorldEntity();
3819
3820         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3821         {
3822                 CHECKGLERROR
3823                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3824                 {
3825                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3826                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3827                 }
3828                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3829                 for (;mesh;mesh = mesh->next)
3830                 {
3831                         r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3832                         if (mesh->vertex3fbuffer)
3833                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3834                         else
3835                                 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3836                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3837                         {
3838                                 // increment stencil if frontface is infront of depthbuffer
3839                                 GL_CullFace(r_refdef.view.cullface_back);
3840                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3841                                 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);
3842                                 // decrement stencil if backface is infront of depthbuffer
3843                                 GL_CullFace(r_refdef.view.cullface_front);
3844                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3845                         }
3846                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3847                         {
3848                                 // decrement stencil if backface is behind depthbuffer
3849                                 GL_CullFace(r_refdef.view.cullface_front);
3850                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3851                                 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);
3852                                 // increment stencil if frontface is behind depthbuffer
3853                                 GL_CullFace(r_refdef.view.cullface_back);
3854                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3855                         }
3856                         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);
3857                 }
3858                 CHECKGLERROR
3859         }
3860         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3861         {
3862                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3863                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3864                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3865                 {
3866                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3867                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3868                                 if (CHECKPVSBIT(trispvs, t))
3869                                         shadowmarklist[numshadowmark++] = t;
3870                 }
3871                 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);
3872         }
3873         else if (numsurfaces)
3874         {
3875                 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);
3876         }
3877
3878         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3879 }
3880
3881 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3882 {
3883         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3884         vec_t relativeshadowradius;
3885         RSurf_ActiveModelEntity(ent, false, false, false);
3886         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3887         // we need to re-init the shader for each entity because the matrix changed
3888         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3889         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3890         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3891         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3892         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3893         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3894         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3895         switch (r_shadow_rendermode)
3896         {
3897         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3898                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3899                 break;
3900         default:
3901                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3902                 break;
3903         }
3904         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3905 }
3906
3907 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3908 {
3909         // set up properties for rendering light onto this entity
3910         RSurf_ActiveModelEntity(ent, true, true, false);
3911         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3912         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3913         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3914         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3915 }
3916
3917 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3918 {
3919         if (!r_refdef.scene.worldmodel->DrawLight)
3920                 return;
3921
3922         // set up properties for rendering light onto this entity
3923         RSurf_ActiveWorldEntity();
3924         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3925         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3926         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3927         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3928
3929         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3930
3931         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3932 }
3933
3934 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3935 {
3936         dp_model_t *model = ent->model;
3937         if (!model->DrawLight)
3938                 return;
3939
3940         R_Shadow_SetupEntityLight(ent);
3941
3942         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3943
3944         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3945 }
3946
3947 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3948 {
3949         int i;
3950         float f;
3951         int numleafs, numsurfaces;
3952         int *leaflist, *surfacelist;
3953         unsigned char *leafpvs;
3954         unsigned char *shadowtrispvs;
3955         unsigned char *lighttrispvs;
3956         //unsigned char *surfacesides;
3957         int numlightentities;
3958         int numlightentities_noselfshadow;
3959         int numshadowentities;
3960         int numshadowentities_noselfshadow;
3961         static entity_render_t *lightentities[MAX_EDICTS];
3962         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3963         static entity_render_t *shadowentities[MAX_EDICTS];
3964         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3965         qboolean nolight;
3966
3967         rtlight->draw = false;
3968
3969         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3970         // skip lights that are basically invisible (color 0 0 0)
3971         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3972
3973         // loading is done before visibility checks because loading should happen
3974         // all at once at the start of a level, not when it stalls gameplay.
3975         // (especially important to benchmarks)
3976         // compile light
3977         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3978         {
3979                 if (rtlight->compiled)
3980                         R_RTLight_Uncompile(rtlight);
3981                 R_RTLight_Compile(rtlight);
3982         }
3983
3984         // load cubemap
3985         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3986
3987         // look up the light style value at this time
3988         f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3989         VectorScale(rtlight->color, f, rtlight->currentcolor);
3990         /*
3991         if (rtlight->selected)
3992         {
3993                 f = 2 + sin(realtime * M_PI * 4.0);
3994                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3995         }
3996         */
3997
3998         // if lightstyle is currently off, don't draw the light
3999         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4000                 return;
4001
4002         // skip processing on corona-only lights
4003         if (nolight)
4004                 return;
4005
4006         // if the light box is offscreen, skip it
4007         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4008                 return;
4009
4010         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4011         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4012
4013         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4014
4015         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4016         {
4017                 // compiled light, world available and can receive realtime lighting
4018                 // retrieve leaf information
4019                 numleafs = rtlight->static_numleafs;
4020                 leaflist = rtlight->static_leaflist;
4021                 leafpvs = rtlight->static_leafpvs;
4022                 numsurfaces = rtlight->static_numsurfaces;
4023                 surfacelist = rtlight->static_surfacelist;
4024                 //surfacesides = NULL;
4025                 shadowtrispvs = rtlight->static_shadowtrispvs;
4026                 lighttrispvs = rtlight->static_lighttrispvs;
4027         }
4028         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4029         {
4030                 // dynamic light, world available and can receive realtime lighting
4031                 // calculate lit surfaces and leafs
4032                 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);
4033                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4034                 leaflist = r_shadow_buffer_leaflist;
4035                 leafpvs = r_shadow_buffer_leafpvs;
4036                 surfacelist = r_shadow_buffer_surfacelist;
4037                 //surfacesides = r_shadow_buffer_surfacesides;
4038                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4039                 lighttrispvs = r_shadow_buffer_lighttrispvs;
4040                 // if the reduced leaf bounds are offscreen, skip it
4041                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4042                         return;
4043         }
4044         else
4045         {
4046                 // no world
4047                 numleafs = 0;
4048                 leaflist = NULL;
4049                 leafpvs = NULL;
4050                 numsurfaces = 0;
4051                 surfacelist = NULL;
4052                 //surfacesides = NULL;
4053                 shadowtrispvs = NULL;
4054                 lighttrispvs = NULL;
4055         }
4056         // check if light is illuminating any visible leafs
4057         if (numleafs)
4058         {
4059                 for (i = 0;i < numleafs;i++)
4060                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4061                                 break;
4062                 if (i == numleafs)
4063                         return;
4064         }
4065
4066         // make a list of lit entities and shadow casting entities
4067         numlightentities = 0;
4068         numlightentities_noselfshadow = 0;
4069         numshadowentities = 0;
4070         numshadowentities_noselfshadow = 0;
4071
4072         // add dynamic entities that are lit by the light
4073         for (i = 0;i < r_refdef.scene.numentities;i++)
4074         {
4075                 dp_model_t *model;
4076                 entity_render_t *ent = r_refdef.scene.entities[i];
4077                 vec3_t org;
4078                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4079                         continue;
4080                 // skip the object entirely if it is not within the valid
4081                 // shadow-casting region (which includes the lit region)
4082                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4083                         continue;
4084                 if (!(model = ent->model))
4085                         continue;
4086                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4087                 {
4088                         // this entity wants to receive light, is visible, and is
4089                         // inside the light box
4090                         // TODO: check if the surfaces in the model can receive light
4091                         // so now check if it's in a leaf seen by the light
4092                         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))
4093                                 continue;
4094                         if (ent->flags & RENDER_NOSELFSHADOW)
4095                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4096                         else
4097                                 lightentities[numlightentities++] = ent;
4098                         // since it is lit, it probably also casts a shadow...
4099                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4100                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4101                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4102                         {
4103                                 // note: exterior models without the RENDER_NOSELFSHADOW
4104                                 // flag still create a RENDER_NOSELFSHADOW shadow but
4105                                 // are lit normally, this means that they are
4106                                 // self-shadowing but do not shadow other
4107                                 // RENDER_NOSELFSHADOW entities such as the gun
4108                                 // (very weird, but keeps the player shadow off the gun)
4109                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4110                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4111                                 else
4112                                         shadowentities[numshadowentities++] = ent;
4113                         }
4114                 }
4115                 else if (ent->flags & RENDER_SHADOW)
4116                 {
4117                         // this entity is not receiving light, but may still need to
4118                         // cast a shadow...
4119                         // TODO: check if the surfaces in the model can cast shadow
4120                         // now check if it is in a leaf seen by the light
4121                         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))
4122                                 continue;
4123                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4124                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4125                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4126                         {
4127                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4128                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4129                                 else
4130                                         shadowentities[numshadowentities++] = ent;
4131                         }
4132                 }
4133         }
4134
4135         // return if there's nothing at all to light
4136         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4137                 return;
4138
4139         // count this light in the r_speeds
4140         r_refdef.stats.lights++;
4141
4142         // flag it as worth drawing later
4143         rtlight->draw = true;
4144
4145         // cache all the animated entities that cast a shadow but are not visible
4146         for (i = 0;i < numshadowentities;i++)
4147                 if (!shadowentities[i]->animcache_vertex3f)
4148                         R_AnimCache_GetEntity(shadowentities[i], false, false);
4149         for (i = 0;i < numshadowentities_noselfshadow;i++)
4150                 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4151                         R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4152
4153         // allocate some temporary memory for rendering this light later in the frame
4154         // reusable buffers need to be copied, static data can be used as-is
4155         rtlight->cached_numlightentities               = numlightentities;
4156         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
4157         rtlight->cached_numshadowentities              = numshadowentities;
4158         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4159         rtlight->cached_numsurfaces                    = numsurfaces;
4160         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4161         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4162         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4163         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4164         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4165         {
4166                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4167                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4168                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4169                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4170                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4171         }
4172         else
4173         {
4174                 // compiled light data
4175                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4176                 rtlight->cached_lighttrispvs = lighttrispvs;
4177                 rtlight->cached_surfacelist = surfacelist;
4178         }
4179 }
4180
4181 void R_Shadow_DrawLight(rtlight_t *rtlight)
4182 {
4183         int i;
4184         int numsurfaces;
4185         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4186         int numlightentities;
4187         int numlightentities_noselfshadow;
4188         int numshadowentities;
4189         int numshadowentities_noselfshadow;
4190         entity_render_t **lightentities;
4191         entity_render_t **lightentities_noselfshadow;
4192         entity_render_t **shadowentities;
4193         entity_render_t **shadowentities_noselfshadow;
4194         int *surfacelist;
4195         static unsigned char entitysides[MAX_EDICTS];
4196         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4197         vec3_t nearestpoint;
4198         vec_t distance;
4199         qboolean castshadows;
4200         int lodlinear;
4201
4202         // check if we cached this light this frame (meaning it is worth drawing)
4203         if (!rtlight->draw)
4204                 return;
4205
4206         numlightentities = rtlight->cached_numlightentities;
4207         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4208         numshadowentities = rtlight->cached_numshadowentities;
4209         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4210         numsurfaces = rtlight->cached_numsurfaces;
4211         lightentities = rtlight->cached_lightentities;
4212         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4213         shadowentities = rtlight->cached_shadowentities;
4214         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4215         shadowtrispvs = rtlight->cached_shadowtrispvs;
4216         lighttrispvs = rtlight->cached_lighttrispvs;
4217         surfacelist = rtlight->cached_surfacelist;
4218
4219         // set up a scissor rectangle for this light
4220         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4221                 return;
4222
4223         // don't let sound skip if going slow
4224         if (r_refdef.scene.extraupdate)
4225                 S_ExtraUpdate ();
4226
4227         // make this the active rtlight for rendering purposes
4228         R_Shadow_RenderMode_ActiveLight(rtlight);
4229
4230         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4231         {
4232                 // optionally draw visible shape of the shadow volumes
4233                 // for performance analysis by level designers
4234                 R_Shadow_RenderMode_VisibleShadowVolumes();
4235                 if (numsurfaces)
4236                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4237                 for (i = 0;i < numshadowentities;i++)
4238                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4239                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4240                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4241                 R_Shadow_RenderMode_VisibleLighting(false, false);
4242         }
4243
4244         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4245         {
4246                 // optionally draw the illuminated areas
4247                 // for performance analysis by level designers
4248                 R_Shadow_RenderMode_VisibleLighting(false, false);
4249                 if (numsurfaces)
4250                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4251                 for (i = 0;i < numlightentities;i++)
4252                         R_Shadow_DrawEntityLight(lightentities[i]);
4253                 for (i = 0;i < numlightentities_noselfshadow;i++)
4254                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4255         }
4256
4257         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4258
4259         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4260         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4261         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4262         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4263
4264         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4265         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4266         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4267
4268         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4269         {
4270                 float borderbias;
4271                 int side;
4272                 int size;
4273                 int castermask = 0;
4274                 int receivermask = 0;
4275                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4276                 Matrix4x4_Abs(&radiustolight);
4277
4278                 r_shadow_shadowmaplod = 0;
4279                 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4280                         if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4281                                 r_shadow_shadowmaplod = i;
4282
4283                 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4284                         
4285                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4286
4287                 surfacesides = NULL;
4288                 if (numsurfaces)
4289                 {
4290                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4291                         {
4292                                 castermask = rtlight->static_shadowmap_casters;
4293                                 receivermask = rtlight->static_shadowmap_receivers;
4294                         }
4295                         else
4296                         {
4297                                 surfacesides = r_shadow_buffer_surfacesides;
4298                                 for(i = 0;i < numsurfaces;i++)
4299                                 {
4300                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4301                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
4302                                         castermask |= surfacesides[i];
4303                                         receivermask |= surfacesides[i];
4304                                 }
4305                         }
4306                 }
4307                 if (receivermask < 0x3F) 
4308                 {
4309                         for (i = 0;i < numlightentities;i++)
4310                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4311                         if (receivermask < 0x3F)
4312                                 for(i = 0; i < numlightentities_noselfshadow;i++)
4313                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4314                 }
4315
4316                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4317
4318                 if (receivermask)
4319                 {
4320                         for (i = 0;i < numshadowentities;i++)
4321                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4322                         for (i = 0;i < numshadowentities_noselfshadow;i++)
4323                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
4324                 }
4325
4326                 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4327
4328                 // render shadow casters into 6 sided depth texture
4329                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4330                 {
4331                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4332                         if (! (castermask & (1 << side))) continue;
4333                         if (numsurfaces)
4334                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4335                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4336                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4337                 }
4338
4339                 if (numlightentities_noselfshadow)
4340                 {
4341                         // render lighting using the depth texture as shadowmap
4342                         // draw lighting in the unmasked areas
4343                         R_Shadow_RenderMode_Lighting(false, false, true);
4344                         for (i = 0;i < numlightentities_noselfshadow;i++)
4345                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4346                 }
4347
4348                 // render shadow casters into 6 sided depth texture
4349                 if (numshadowentities_noselfshadow)
4350                 {
4351                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4352                         {
4353                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4354                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4355                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4356                         }
4357                 }
4358
4359                 // render lighting using the depth texture as shadowmap
4360                 // draw lighting in the unmasked areas
4361                 R_Shadow_RenderMode_Lighting(false, false, true);
4362                 // draw lighting in the unmasked areas
4363                 if (numsurfaces)
4364                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4365                 for (i = 0;i < numlightentities;i++)
4366                         R_Shadow_DrawEntityLight(lightentities[i]);
4367         }
4368         else if (castshadows && vid.stencil)
4369         {
4370                 // draw stencil shadow volumes to mask off pixels that are in shadow
4371                 // so that they won't receive lighting
4372                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4373                 R_Shadow_ClearStencil();
4374
4375                 if (numsurfaces)
4376                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4377                 for (i = 0;i < numshadowentities;i++)
4378                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4379
4380                 // draw lighting in the unmasked areas
4381                 R_Shadow_RenderMode_Lighting(true, false, false);
4382                 for (i = 0;i < numlightentities_noselfshadow;i++)
4383                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4384
4385                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4386                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4387
4388                 // draw lighting in the unmasked areas
4389                 R_Shadow_RenderMode_Lighting(true, false, false);
4390                 if (numsurfaces)
4391                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4392                 for (i = 0;i < numlightentities;i++)
4393                         R_Shadow_DrawEntityLight(lightentities[i]);
4394         }
4395         else
4396         {
4397                 // draw lighting in the unmasked areas
4398                 R_Shadow_RenderMode_Lighting(false, false, false);
4399                 if (numsurfaces)
4400                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4401                 for (i = 0;i < numlightentities;i++)
4402                         R_Shadow_DrawEntityLight(lightentities[i]);
4403                 for (i = 0;i < numlightentities_noselfshadow;i++)
4404                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4405         }
4406
4407         if (r_shadow_usingdeferredprepass)
4408         {
4409                 // when rendering deferred lighting, we simply rasterize the box
4410                 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4411                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
4412                 else if (castshadows && vid.stencil)
4413                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
4414                 else
4415                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
4416         }
4417 }
4418
4419 static void R_Shadow_FreeDeferred(void)
4420 {
4421         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4422         r_shadow_prepassgeometryfbo = 0;
4423
4424         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4425         r_shadow_prepasslightingdiffusespecularfbo = 0;
4426
4427         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4428         r_shadow_prepasslightingdiffusefbo = 0;
4429
4430         if (r_shadow_prepassgeometrydepthtexture)
4431                 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4432         r_shadow_prepassgeometrydepthtexture = NULL;
4433
4434         if (r_shadow_prepassgeometrydepthcolortexture)
4435                 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4436         r_shadow_prepassgeometrydepthcolortexture = NULL;
4437
4438         if (r_shadow_prepassgeometrynormalmaptexture)
4439                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4440         r_shadow_prepassgeometrynormalmaptexture = NULL;
4441
4442         if (r_shadow_prepasslightingdiffusetexture)
4443                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4444         r_shadow_prepasslightingdiffusetexture = NULL;
4445
4446         if (r_shadow_prepasslightingspeculartexture)
4447                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4448         r_shadow_prepasslightingspeculartexture = NULL;
4449 }
4450
4451 void R_Shadow_DrawPrepass(void)
4452 {
4453         int i;
4454         int flag;
4455         int lnum;
4456         size_t lightindex;
4457         dlight_t *light;
4458         size_t range;
4459         entity_render_t *ent;
4460         float clearcolor[4];
4461
4462         R_Mesh_ResetTextureState();
4463         GL_DepthMask(true);
4464         GL_ColorMask(1,1,1,1);
4465         GL_BlendFunc(GL_ONE, GL_ZERO);
4466         GL_Color(1,1,1,1);
4467         GL_DepthTest(true);
4468         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4469         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4470         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4471         if (r_timereport_active)
4472                 R_TimeReport("prepasscleargeom");
4473
4474         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4475                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4476         if (r_timereport_active)
4477                 R_TimeReport("prepassworld");
4478
4479         for (i = 0;i < r_refdef.scene.numentities;i++)
4480         {
4481                 if (!r_refdef.viewcache.entityvisible[i])
4482                         continue;
4483                 ent = r_refdef.scene.entities[i];
4484                 if (ent->model && ent->model->DrawPrepass != NULL)
4485                         ent->model->DrawPrepass(ent);
4486         }
4487
4488         if (r_timereport_active)
4489                 R_TimeReport("prepassmodels");
4490
4491         GL_DepthMask(false);
4492         GL_ColorMask(1,1,1,1);
4493         GL_Color(1,1,1,1);
4494         GL_DepthTest(true);
4495         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4496         Vector4Set(clearcolor, 0, 0, 0, 0);
4497         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4498         if (r_timereport_active)
4499                 R_TimeReport("prepassclearlit");
4500
4501         R_Shadow_RenderMode_Begin();
4502
4503         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4504         if (r_shadow_debuglight.integer >= 0)
4505         {
4506                 lightindex = r_shadow_debuglight.integer;
4507                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4508                 if (light && (light->flags & flag) && light->rtlight.draw)
4509                         R_Shadow_DrawLight(&light->rtlight);
4510         }
4511         else
4512         {
4513                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4514                 for (lightindex = 0;lightindex < range;lightindex++)
4515                 {
4516                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4517                         if (light && (light->flags & flag) && light->rtlight.draw)
4518                                 R_Shadow_DrawLight(&light->rtlight);
4519                 }
4520         }
4521         if (r_refdef.scene.rtdlight)
4522                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4523                         if (r_refdef.scene.lights[lnum]->draw)
4524                                 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4525
4526         R_Mesh_ResetRenderTargets();
4527
4528         R_Shadow_RenderMode_End();
4529
4530         if (r_timereport_active)
4531                 R_TimeReport("prepasslights");
4532 }
4533
4534 void R_Shadow_DrawLightSprites(void);
4535 void R_Shadow_PrepareLights(void)
4536 {
4537         int flag;
4538         int lnum;
4539         size_t lightindex;
4540         dlight_t *light;
4541         size_t range;
4542         float f;
4543         GLenum status;
4544
4545         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4546                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4547                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
4548                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4549                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4550                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4551                 R_Shadow_FreeShadowMaps();
4552
4553         r_shadow_usingshadowmaportho = false;
4554
4555         switch (vid.renderpath)
4556         {
4557         case RENDERPATH_GL20:
4558         case RENDERPATH_D3D9:
4559         case RENDERPATH_D3D10:
4560         case RENDERPATH_D3D11:
4561         case RENDERPATH_SOFT:
4562         case RENDERPATH_GLES2:
4563                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4564                 {
4565                         r_shadow_usingdeferredprepass = false;
4566                         if (r_shadow_prepass_width)
4567                                 R_Shadow_FreeDeferred();
4568                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4569                         break;
4570                 }
4571
4572                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4573                 {
4574                         R_Shadow_FreeDeferred();
4575
4576                         r_shadow_usingdeferredprepass = true;
4577                         r_shadow_prepass_width = vid.width;
4578                         r_shadow_prepass_height = vid.height;
4579                         r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4580                         switch (vid.renderpath)
4581                         {
4582                         case RENDERPATH_D3D9:
4583                                 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);
4584                                 break;
4585                         default:
4586                                 break;
4587                         }
4588                         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);
4589                         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);
4590                         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);
4591
4592                         // set up the geometry pass fbo (depth + normalmap)
4593                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4594                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4595                         // render depth into one texture and normalmap into the other
4596                         if (qglDrawBuffersARB)
4597                         {
4598                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4599                                 qglReadBuffer(GL_NONE);CHECKGLERROR
4600                                 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4601                                 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4602                                 {
4603                                         Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4604                                         Cvar_SetValueQuick(&r_shadow_deferred, 0);
4605                                         r_shadow_usingdeferredprepass = false;
4606                                 }
4607                         }
4608
4609                         // set up the lighting pass fbo (diffuse + specular)
4610                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4611                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4612                         // render diffuse into one texture and specular into another,
4613                         // with depth and normalmap bound as textures,
4614                         // with depth bound as attachment as well
4615                         if (qglDrawBuffersARB)
4616                         {
4617                                 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);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)
4629                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4630                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4631                         // render diffuse into one texture,
4632                         // with depth and normalmap bound as textures,
4633                         // with depth bound as attachment as well
4634                         if (qglDrawBuffersARB)
4635                         {
4636                                 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);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                 break;
4648         case RENDERPATH_GL13:
4649         case RENDERPATH_GL11:
4650                 r_shadow_usingdeferredprepass = false;
4651                 break;
4652         }
4653
4654         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);
4655
4656         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4657         if (r_shadow_debuglight.integer >= 0)
4658         {
4659                 lightindex = r_shadow_debuglight.integer;
4660                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4661                 if (light && (light->flags & flag))
4662                         R_Shadow_PrepareLight(&light->rtlight);
4663         }
4664         else
4665         {
4666                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4667                 for (lightindex = 0;lightindex < range;lightindex++)
4668                 {
4669                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4670                         if (light && (light->flags & flag))
4671                                 R_Shadow_PrepareLight(&light->rtlight);
4672                 }
4673         }
4674         if (r_refdef.scene.rtdlight)
4675         {
4676                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4677                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4678         }
4679         else if(gl_flashblend.integer)
4680         {
4681                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4682                 {
4683                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4684                         f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4685                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4686                 }
4687         }
4688
4689         if (r_editlights.integer)
4690                 R_Shadow_DrawLightSprites();
4691
4692         R_Shadow_UpdateBounceGridTexture();
4693 }
4694
4695 void R_Shadow_DrawLights(void)
4696 {
4697         int flag;
4698         int lnum;
4699         size_t lightindex;
4700         dlight_t *light;
4701         size_t range;
4702
4703         R_Shadow_RenderMode_Begin();
4704
4705         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4706         if (r_shadow_debuglight.integer >= 0)
4707         {
4708                 lightindex = r_shadow_debuglight.integer;
4709                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4710                 if (light && (light->flags & flag))
4711                         R_Shadow_DrawLight(&light->rtlight);
4712         }
4713         else
4714         {
4715                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4716                 for (lightindex = 0;lightindex < range;lightindex++)
4717                 {
4718                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4719                         if (light && (light->flags & flag))
4720                                 R_Shadow_DrawLight(&light->rtlight);
4721                 }
4722         }
4723         if (r_refdef.scene.rtdlight)
4724                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4725                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4726
4727         R_Shadow_RenderMode_End();
4728 }
4729
4730 extern const float r_screenvertex3f[12];
4731 extern void R_SetupView(qboolean allowwaterclippingplane);
4732 extern void R_ResetViewRendering3D(void);
4733 extern void R_ResetViewRendering2D(void);
4734 extern cvar_t r_shadows;
4735 extern cvar_t r_shadows_darken;
4736 extern cvar_t r_shadows_drawafterrtlighting;
4737 extern cvar_t r_shadows_castfrombmodels;
4738 extern cvar_t r_shadows_throwdistance;
4739 extern cvar_t r_shadows_throwdirection;
4740 extern cvar_t r_shadows_focus;
4741 extern cvar_t r_shadows_shadowmapscale;
4742
4743 void R_Shadow_PrepareModelShadows(void)
4744 {
4745         int i;
4746         float scale, size, radius, dot1, dot2;
4747         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4748         entity_render_t *ent;
4749
4750         if (!r_refdef.scene.numentities)
4751                 return;
4752
4753         switch (r_shadow_shadowmode)
4754         {
4755         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4756                 if (r_shadows.integer >= 2) 
4757                         break;
4758                 // fall through
4759         case R_SHADOW_SHADOWMODE_STENCIL:
4760                 for (i = 0;i < r_refdef.scene.numentities;i++)
4761                 {
4762                         ent = r_refdef.scene.entities[i];
4763                         if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4764                                 R_AnimCache_GetEntity(ent, false, false);
4765                 }
4766                 return;
4767         default:
4768                 return;
4769         }
4770
4771         size = 2*r_shadow_shadowmapmaxsize;
4772         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4773         radius = 0.5f * size / scale;
4774
4775         Math_atov(r_shadows_throwdirection.string, shadowdir);
4776         VectorNormalize(shadowdir);
4777         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4778         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4779         if (fabs(dot1) <= fabs(dot2))
4780                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4781         else
4782                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4783         VectorNormalize(shadowforward);
4784         CrossProduct(shadowdir, shadowforward, shadowright);
4785         Math_atov(r_shadows_focus.string, shadowfocus);
4786         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4787         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4788         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4789         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4790         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4791                 dot1 = 1;
4792         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4793
4794         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4795         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4796         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4797         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4798         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4799         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4800
4801         for (i = 0;i < r_refdef.scene.numentities;i++)
4802         {
4803                 ent = r_refdef.scene.entities[i];
4804                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4805                         continue;
4806                 // cast shadows from anything of the map (submodels are optional)
4807                 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4808                         R_AnimCache_GetEntity(ent, false, false);
4809         }
4810 }
4811
4812 void R_DrawModelShadowMaps(void)
4813 {
4814         int i;
4815         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4816         entity_render_t *ent;
4817         vec3_t relativelightorigin;
4818         vec3_t relativelightdirection, relativeforward, relativeright;
4819         vec3_t relativeshadowmins, relativeshadowmaxs;
4820         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4821         float m[12];
4822         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4823         r_viewport_t viewport;
4824         GLuint fbo = 0;
4825         float clearcolor[4];
4826
4827         if (!r_refdef.scene.numentities)
4828                 return;
4829
4830         switch (r_shadow_shadowmode)
4831         {
4832         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4833                 break;
4834         default:
4835                 return;
4836         }
4837
4838         R_ResetViewRendering3D();
4839         R_Shadow_RenderMode_Begin();
4840         R_Shadow_RenderMode_ActiveLight(NULL);
4841
4842         switch (r_shadow_shadowmode)
4843         {
4844         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4845                 if (!r_shadow_shadowmap2dtexture)
4846                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4847                 fbo = r_shadow_fbo2d;
4848                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4849                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4850                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4851                 break;
4852         default:
4853                 break;
4854         }
4855
4856         size = 2*r_shadow_shadowmapmaxsize;
4857         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4858         radius = 0.5f / scale;
4859         nearclip = -r_shadows_throwdistance.value;
4860         farclip = r_shadows_throwdistance.value;
4861         bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4862
4863         r_shadow_shadowmap_parameters[0] = size;
4864         r_shadow_shadowmap_parameters[1] = size;
4865         r_shadow_shadowmap_parameters[2] = 1.0;
4866         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4867
4868         Math_atov(r_shadows_throwdirection.string, shadowdir);
4869         VectorNormalize(shadowdir);
4870         Math_atov(r_shadows_focus.string, shadowfocus);
4871         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4872         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4873         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4874         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4875         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4876         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4877         if (fabs(dot1) <= fabs(dot2)) 
4878                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4879         else
4880                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4881         VectorNormalize(shadowforward);
4882         VectorM(scale, shadowforward, &m[0]);
4883         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4884                 dot1 = 1;
4885         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4886         CrossProduct(shadowdir, shadowforward, shadowright);
4887         VectorM(scale, shadowright, &m[4]);
4888         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4889         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4890         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4891         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4892         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4893         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
4894
4895         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4896
4897         R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4898         R_SetupShader_DepthOrShadow();
4899         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4900         GL_DepthMask(true);
4901         GL_DepthTest(true);
4902         R_SetViewport(&viewport);
4903         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4904         Vector4Set(clearcolor, 1,1,1,1);
4905         // in D3D9 we have to render to a color texture shadowmap
4906         // in GL we render directly to a depth texture only
4907         if (r_shadow_shadowmap2dtexture)
4908                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4909         else
4910                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4911         // render into a slightly restricted region so that the borders of the
4912         // shadowmap area fade away, rather than streaking across everything
4913         // outside the usable area
4914         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4915
4916 #if 0
4917         // debugging
4918         R_Mesh_ResetRenderTargets();
4919         R_SetupShader_ShowDepth();
4920         GL_ColorMask(1,1,1,1);
4921         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4922 #endif
4923
4924         for (i = 0;i < r_refdef.scene.numentities;i++)
4925         {
4926                 ent = r_refdef.scene.entities[i];
4927
4928                 // cast shadows from anything of the map (submodels are optional)
4929                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4930                 {
4931                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4932                         Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4933                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4934                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4935                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4936                         relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4937                         relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4938                         relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4939                         relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4940                         relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4941                         relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4942                         RSurf_ActiveModelEntity(ent, false, false, false);
4943                         ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4944                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4945                 }
4946         }
4947
4948 #if 0
4949         if (r_test.integer)
4950         {
4951                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4952                 CHECKGLERROR
4953                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4954                 CHECKGLERROR
4955                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4956                 Cvar_SetValueQuick(&r_test, 0);
4957                 Z_Free(rawpixels);
4958         }
4959 #endif
4960
4961         R_Shadow_RenderMode_End();
4962
4963         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4964         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4965         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
4966         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4967         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4968         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4969
4970         switch (vid.renderpath)
4971         {
4972         case RENDERPATH_GL11:
4973         case RENDERPATH_GL13:
4974         case RENDERPATH_GL20:
4975         case RENDERPATH_SOFT:
4976         case RENDERPATH_GLES2:
4977                 break;
4978         case RENDERPATH_D3D9:
4979         case RENDERPATH_D3D10:
4980         case RENDERPATH_D3D11:
4981 #ifdef OPENGL_ORIENTATION
4982                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4983                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
4984                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
4985                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
4986 #else
4987                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
4988                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
4989                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
4990                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
4991 #endif
4992                 break;
4993         }
4994
4995         r_shadow_usingshadowmaportho = true;
4996         switch (r_shadow_shadowmode)
4997         {
4998         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4999                 r_shadow_usingshadowmap2d = true;
5000                 break;
5001         default:
5002                 break;
5003         }
5004 }
5005
5006 void R_DrawModelShadows(void)
5007 {
5008         int i;
5009         float relativethrowdistance;
5010         entity_render_t *ent;
5011         vec3_t relativelightorigin;
5012         vec3_t relativelightdirection;
5013         vec3_t relativeshadowmins, relativeshadowmaxs;
5014         vec3_t tmp, shadowdir;
5015
5016         if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5017                 return;
5018
5019         R_ResetViewRendering3D();
5020         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5021         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5022         R_Shadow_RenderMode_Begin();
5023         R_Shadow_RenderMode_ActiveLight(NULL);
5024         r_shadow_lightscissor[0] = r_refdef.view.x;
5025         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5026         r_shadow_lightscissor[2] = r_refdef.view.width;
5027         r_shadow_lightscissor[3] = r_refdef.view.height;
5028         R_Shadow_RenderMode_StencilShadowVolumes(false);
5029
5030         // get shadow dir
5031         if (r_shadows.integer == 2)
5032         {
5033                 Math_atov(r_shadows_throwdirection.string, shadowdir);
5034                 VectorNormalize(shadowdir);
5035         }
5036
5037         R_Shadow_ClearStencil();
5038
5039         for (i = 0;i < r_refdef.scene.numentities;i++)
5040         {
5041                 ent = r_refdef.scene.entities[i];
5042
5043                 // cast shadows from anything of the map (submodels are optional)
5044                 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5045                 {
5046                         relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5047                         VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5048                         VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5049                         if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5050                                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5051                         else
5052                         {
5053                                 if(ent->entitynumber != 0)
5054                                 {
5055                                         if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5056                                         {
5057                                                 // FIXME handle this
5058                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5059                                         }
5060                                         else
5061                                         {
5062                                                 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5063                                                 int entnum, entnum2, recursion;
5064                                                 entnum = entnum2 = ent->entitynumber;
5065                                                 for(recursion = 32; recursion > 0; --recursion)
5066                                                 {
5067                                                         entnum2 = cl.entities[entnum].state_current.tagentity;
5068                                                         if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5069                                                                 entnum = entnum2;
5070                                                         else
5071                                                                 break;
5072                                                 }
5073                                                 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5074                                                 {
5075                                                         VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5076                                                         // transform into modelspace of OUR entity
5077                                                         Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5078                                                         Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5079                                                 }
5080                                                 else
5081                                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5082                                         }
5083                                 }
5084                                 else
5085                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5086                         }
5087
5088                         VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5089                         RSurf_ActiveModelEntity(ent, false, false, false);
5090                         ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5091                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5092                 }
5093         }
5094
5095         // not really the right mode, but this will disable any silly stencil features
5096         R_Shadow_RenderMode_End();
5097
5098         // set up ortho view for rendering this pass
5099         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5100         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5101         //GL_ScissorTest(true);
5102         //R_EntityMatrix(&identitymatrix);
5103         //R_Mesh_ResetTextureState();
5104         R_ResetViewRendering2D();
5105
5106         // set up a darkening blend on shadowed areas
5107         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5108         //GL_DepthRange(0, 1);
5109         //GL_DepthTest(false);
5110         //GL_DepthMask(false);
5111         //GL_PolygonOffset(0, 0);CHECKGLERROR
5112         GL_Color(0, 0, 0, r_shadows_darken.value);
5113         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5114         //GL_DepthFunc(GL_ALWAYS);
5115         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5116
5117         // apply the blend to the shadowed areas
5118         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5119         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5120         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5121
5122         // restore the viewport
5123         R_SetViewport(&r_refdef.view.viewport);
5124
5125         // restore other state to normal
5126         //R_Shadow_RenderMode_End();
5127 }
5128
5129 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5130 {
5131         float zdist;
5132         vec3_t centerorigin;
5133         float vertex3f[12];
5134         // if it's too close, skip it
5135         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5136                 return;
5137         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5138         if (zdist < 32)
5139                 return;
5140         if (usequery && r_numqueries + 2 <= r_maxqueries)
5141         {
5142                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5143                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5144                 // 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
5145                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5146
5147                 switch(vid.renderpath)
5148                 {
5149                 case RENDERPATH_GL20:
5150                 case RENDERPATH_GL13:
5151                 case RENDERPATH_GL11:
5152                 case RENDERPATH_GLES2:
5153                         CHECKGLERROR
5154                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5155                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5156                         GL_DepthFunc(GL_ALWAYS);
5157                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5158                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5159                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5160                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5161                         GL_DepthFunc(GL_LEQUAL);
5162                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5163                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5164                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5165                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5166                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5167                         CHECKGLERROR
5168                         break;
5169                 case RENDERPATH_D3D9:
5170                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5171                         break;
5172                 case RENDERPATH_D3D10:
5173                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5174                         break;
5175                 case RENDERPATH_D3D11:
5176                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5177                         break;
5178                 case RENDERPATH_SOFT:
5179                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5180                         break;
5181                 }
5182         }
5183         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5184 }
5185
5186 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5187
5188 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5189 {
5190         vec3_t color;
5191         GLint allpixels = 0, visiblepixels = 0;
5192         // now we have to check the query result
5193         if (rtlight->corona_queryindex_visiblepixels)
5194         {
5195                 switch(vid.renderpath)
5196                 {
5197                 case RENDERPATH_GL20:
5198                 case RENDERPATH_GL13:
5199                 case RENDERPATH_GL11:
5200                 case RENDERPATH_GLES2:
5201                         CHECKGLERROR
5202                         qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5203                         qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5204                         CHECKGLERROR
5205                         break;
5206                 case RENDERPATH_D3D9:
5207                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5208                         break;
5209                 case RENDERPATH_D3D10:
5210                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5211                         break;
5212                 case RENDERPATH_D3D11:
5213                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5214                         break;
5215                 case RENDERPATH_SOFT:
5216                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5217                         break;
5218                 }
5219                 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5220                 if (visiblepixels < 1 || allpixels < 1)
5221                         return;
5222                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5223                 cscale *= rtlight->corona_visibility;
5224         }
5225         else
5226         {
5227                 // FIXME: these traces should scan all render entities instead of cl.world
5228                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
5229                         return;
5230         }
5231         VectorScale(rtlight->currentcolor, cscale, color);
5232         if (VectorLength(color) > (1.0f / 256.0f))
5233         {
5234                 float vertex3f[12];
5235                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5236                 if(negated)
5237                 {
5238                         VectorNegate(color, color);
5239                         switch(vid.renderpath)
5240                         {
5241                         case RENDERPATH_GL11:
5242                         case RENDERPATH_GL13:
5243                         case RENDERPATH_GL20:
5244                         case RENDERPATH_GLES2:
5245                                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5246                                 break;
5247                         case RENDERPATH_D3D9:
5248 #ifdef SUPPORTD3D
5249                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5250 #endif
5251                                 break;
5252                         case RENDERPATH_D3D10:
5253                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5254                                 break;
5255                         case RENDERPATH_D3D11:
5256                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5257                                 break;
5258                         case RENDERPATH_SOFT:
5259                                 DPSOFTRAST_BlendSubtract(true);
5260                                 break;
5261                         }
5262                 }
5263                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5264                 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);
5265                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5266                 if(negated)
5267                 {
5268                         switch(vid.renderpath)
5269                         {
5270                         case RENDERPATH_GL11:
5271                         case RENDERPATH_GL13:
5272                         case RENDERPATH_GL20:
5273                         case RENDERPATH_GLES2:
5274                                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5275                                 break;
5276                         case RENDERPATH_D3D9:
5277 #ifdef SUPPORTD3D
5278                                 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5279 #endif
5280                                 break;
5281                         case RENDERPATH_D3D10:
5282                                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5283                                 break;
5284                         case RENDERPATH_D3D11:
5285                                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5286                                 break;
5287                         case RENDERPATH_SOFT:
5288                                 DPSOFTRAST_BlendSubtract(false);
5289                                 break;
5290                         }
5291                 }
5292         }
5293 }
5294
5295 void R_Shadow_DrawCoronas(void)
5296 {
5297         int i, flag;
5298         qboolean usequery = false;
5299         size_t lightindex;
5300         dlight_t *light;
5301         rtlight_t *rtlight;
5302         size_t range;
5303         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5304                 return;
5305         if (r_waterstate.renderingscene)
5306                 return;
5307         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5308         R_EntityMatrix(&identitymatrix);
5309
5310         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5311
5312         // check occlusion of coronas
5313         // use GL_ARB_occlusion_query if available
5314         // otherwise use raytraces
5315         r_numqueries = 0;
5316         switch (vid.renderpath)
5317         {
5318         case RENDERPATH_GL11:
5319         case RENDERPATH_GL13:
5320         case RENDERPATH_GL20:
5321         case RENDERPATH_GLES2:
5322                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5323                 if (usequery)
5324                 {
5325                         GL_ColorMask(0,0,0,0);
5326                         if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5327                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5328                         {
5329                                 i = r_maxqueries;
5330                                 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5331                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5332                                 CHECKGLERROR
5333                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5334                                 CHECKGLERROR
5335                         }
5336                         RSurf_ActiveWorldEntity();
5337                         GL_BlendFunc(GL_ONE, GL_ZERO);
5338                         GL_CullFace(GL_NONE);
5339                         GL_DepthMask(false);
5340                         GL_DepthRange(0, 1);
5341                         GL_PolygonOffset(0, 0);
5342                         GL_DepthTest(true);
5343                         R_Mesh_ResetTextureState();
5344                         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5345                 }
5346                 break;
5347         case RENDERPATH_D3D9:
5348                 usequery = false;
5349                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5350                 break;
5351         case RENDERPATH_D3D10:
5352                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5353                 break;
5354         case RENDERPATH_D3D11:
5355                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5356                 break;
5357         case RENDERPATH_SOFT:
5358                 usequery = false;
5359                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5360                 break;
5361         }
5362         for (lightindex = 0;lightindex < range;lightindex++)
5363         {
5364                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5365                 if (!light)
5366                         continue;
5367                 rtlight = &light->rtlight;
5368                 rtlight->corona_visibility = 0;
5369                 rtlight->corona_queryindex_visiblepixels = 0;
5370                 rtlight->corona_queryindex_allpixels = 0;
5371                 if (!(rtlight->flags & flag))
5372                         continue;
5373                 if (rtlight->corona <= 0)
5374                         continue;
5375                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5376                         continue;
5377                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5378         }
5379         for (i = 0;i < r_refdef.scene.numlights;i++)
5380         {
5381                 rtlight = r_refdef.scene.lights[i];
5382                 rtlight->corona_visibility = 0;
5383                 rtlight->corona_queryindex_visiblepixels = 0;
5384                 rtlight->corona_queryindex_allpixels = 0;
5385                 if (!(rtlight->flags & flag))
5386                         continue;
5387                 if (rtlight->corona <= 0)
5388                         continue;
5389                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5390         }
5391         if (usequery)
5392                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5393
5394         // now draw the coronas using the query data for intensity info
5395         for (lightindex = 0;lightindex < range;lightindex++)
5396         {
5397                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5398                 if (!light)
5399                         continue;
5400                 rtlight = &light->rtlight;
5401                 if (rtlight->corona_visibility <= 0)
5402                         continue;
5403                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5404         }
5405         for (i = 0;i < r_refdef.scene.numlights;i++)
5406         {
5407                 rtlight = r_refdef.scene.lights[i];
5408                 if (rtlight->corona_visibility <= 0)
5409                         continue;
5410                 if (gl_flashblend.integer)
5411                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5412                 else
5413                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5414         }
5415 }
5416
5417
5418
5419 dlight_t *R_Shadow_NewWorldLight(void)
5420 {
5421         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5422 }
5423
5424 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)
5425 {
5426         matrix4x4_t matrix;
5427         // validate parameters
5428         if (style < 0 || style >= MAX_LIGHTSTYLES)
5429         {
5430                 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5431                 style = 0;
5432         }
5433         if (!cubemapname)
5434                 cubemapname = "";
5435
5436         // copy to light properties
5437         VectorCopy(origin, light->origin);
5438         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5439         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5440         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5441         /*
5442         light->color[0] = max(color[0], 0);
5443         light->color[1] = max(color[1], 0);
5444         light->color[2] = max(color[2], 0);
5445         */
5446         light->color[0] = color[0];
5447         light->color[1] = color[1];
5448         light->color[2] = color[2];
5449         light->radius = max(radius, 0);
5450         light->style = style;
5451         light->shadow = shadowenable;
5452         light->corona = corona;
5453         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5454         light->coronasizescale = coronasizescale;
5455         light->ambientscale = ambientscale;
5456         light->diffusescale = diffusescale;
5457         light->specularscale = specularscale;
5458         light->flags = flags;
5459
5460         // update renderable light data
5461         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5462         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);
5463 }
5464
5465 void R_Shadow_FreeWorldLight(dlight_t *light)
5466 {
5467         if (r_shadow_selectedlight == light)
5468                 r_shadow_selectedlight = NULL;
5469         R_RTLight_Uncompile(&light->rtlight);
5470         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5471 }
5472
5473 void R_Shadow_ClearWorldLights(void)
5474 {
5475         size_t lightindex;
5476         dlight_t *light;
5477         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5478         for (lightindex = 0;lightindex < range;lightindex++)
5479         {
5480                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5481                 if (light)
5482                         R_Shadow_FreeWorldLight(light);
5483         }
5484         r_shadow_selectedlight = NULL;
5485 }
5486
5487 void R_Shadow_SelectLight(dlight_t *light)
5488 {
5489         if (r_shadow_selectedlight)
5490                 r_shadow_selectedlight->selected = false;
5491         r_shadow_selectedlight = light;
5492         if (r_shadow_selectedlight)
5493                 r_shadow_selectedlight->selected = true;
5494 }
5495
5496 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5497 {
5498         // this is never batched (there can be only one)
5499         float vertex3f[12];
5500         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5501         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5502         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5503 }
5504
5505 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5506 {
5507         float intensity;
5508         float s;
5509         vec3_t spritecolor;
5510         skinframe_t *skinframe;
5511         float vertex3f[12];
5512
5513         // this is never batched (due to the ent parameter changing every time)
5514         // so numsurfaces == 1 and surfacelist[0] == lightnumber
5515         const dlight_t *light = (dlight_t *)ent;
5516         s = EDLIGHTSPRSIZE;
5517
5518         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5519
5520         intensity = 0.5f;
5521         VectorScale(light->color, intensity, spritecolor);
5522         if (VectorLength(spritecolor) < 0.1732f)
5523                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5524         if (VectorLength(spritecolor) > 1.0f)
5525                 VectorNormalize(spritecolor);
5526
5527         // draw light sprite
5528         if (light->cubemapname[0] && !light->shadow)
5529                 skinframe = r_editlights_sprcubemapnoshadowlight;
5530         else if (light->cubemapname[0])
5531                 skinframe = r_editlights_sprcubemaplight;
5532         else if (!light->shadow)
5533                 skinframe = r_editlights_sprnoshadowlight;
5534         else
5535                 skinframe = r_editlights_sprlight;
5536
5537         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);
5538         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5539
5540         // draw selection sprite if light is selected
5541         if (light->selected)
5542         {
5543                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5544                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5545                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5546         }
5547 }
5548
5549 void R_Shadow_DrawLightSprites(void)
5550 {
5551         size_t lightindex;
5552         dlight_t *light;
5553         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5554         for (lightindex = 0;lightindex < range;lightindex++)
5555         {
5556                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5557                 if (light)
5558                         R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5559         }
5560         if (!r_editlights_lockcursor)
5561                 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5562 }
5563
5564 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5565 {
5566         unsigned int range;
5567         dlight_t *light;
5568         rtlight_t *rtlight;
5569         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5570         if (lightindex >= range)
5571                 return -1;
5572         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5573         if (!light)
5574                 return 0;
5575         rtlight = &light->rtlight;
5576         //if (!(rtlight->flags & flag))
5577         //      return 0;
5578         VectorCopy(rtlight->shadoworigin, origin);
5579         *radius = rtlight->radius;
5580         VectorCopy(rtlight->color, color);
5581         return 1;
5582 }
5583
5584 void R_Shadow_SelectLightInView(void)
5585 {
5586         float bestrating, rating, temp[3];
5587         dlight_t *best;
5588         size_t lightindex;
5589         dlight_t *light;
5590         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5591         best = NULL;
5592         bestrating = 0;
5593
5594         if (r_editlights_lockcursor)
5595                 return;
5596         for (lightindex = 0;lightindex < range;lightindex++)
5597         {
5598                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5599                 if (!light)
5600                         continue;
5601                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5602                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5603                 if (rating >= 0.95)
5604                 {
5605                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5606                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5607                         {
5608                                 bestrating = rating;
5609                                 best = light;
5610                         }
5611                 }
5612         }
5613         R_Shadow_SelectLight(best);
5614 }
5615
5616 void R_Shadow_LoadWorldLights(void)
5617 {
5618         int n, a, style, shadow, flags;
5619         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5620         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5621         if (cl.worldmodel == NULL)
5622         {
5623                 Con_Print("No map loaded.\n");
5624                 return;
5625         }
5626         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5627         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5628         if (lightsstring)
5629         {
5630                 s = lightsstring;
5631                 n = 0;
5632                 while (*s)
5633                 {
5634                         t = s;
5635                         /*
5636                         shadow = true;
5637                         for (;COM_Parse(t, true) && strcmp(
5638                         if (COM_Parse(t, true))
5639                         {
5640                                 if (com_token[0] == '!')
5641                                 {
5642                                         shadow = false;
5643                                         origin[0] = atof(com_token+1);
5644                                 }
5645                                 else
5646                                         origin[0] = atof(com_token);
5647                                 if (Com_Parse(t
5648                         }
5649                         */
5650                         t = s;
5651                         while (*s && *s != '\n' && *s != '\r')
5652                                 s++;
5653                         if (!*s)
5654                                 break;
5655                         tempchar = *s;
5656                         shadow = true;
5657                         // check for modifier flags
5658                         if (*t == '!')
5659                         {
5660                                 shadow = false;
5661                                 t++;
5662                         }
5663                         *s = 0;
5664 #if _MSC_VER >= 1400
5665 #define sscanf sscanf_s
5666 #endif
5667                         cubemapname[sizeof(cubemapname)-1] = 0;
5668 #if MAX_QPATH != 128
5669 #error update this code if MAX_QPATH changes
5670 #endif
5671                         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
5672 #if _MSC_VER >= 1400
5673 , sizeof(cubemapname)
5674 #endif
5675 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5676                         *s = tempchar;
5677                         if (a < 18)
5678                                 flags = LIGHTFLAG_REALTIMEMODE;
5679                         if (a < 17)
5680                                 specularscale = 1;
5681                         if (a < 16)
5682                                 diffusescale = 1;
5683                         if (a < 15)
5684                                 ambientscale = 0;
5685                         if (a < 14)
5686                                 coronasizescale = 0.25f;
5687                         if (a < 13)
5688                                 VectorClear(angles);
5689                         if (a < 10)
5690                                 corona = 0;
5691                         if (a < 9 || !strcmp(cubemapname, "\"\""))
5692                                 cubemapname[0] = 0;
5693                         // remove quotes on cubemapname
5694                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5695                         {
5696                                 size_t namelen;
5697                                 namelen = strlen(cubemapname) - 2;
5698                                 memmove(cubemapname, cubemapname + 1, namelen);
5699                                 cubemapname[namelen] = '\0';
5700                         }
5701                         if (a < 8)
5702                         {
5703                                 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);
5704                                 break;
5705                         }
5706                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5707                         if (*s == '\r')
5708                                 s++;
5709                         if (*s == '\n')
5710                                 s++;
5711                         n++;
5712                 }
5713                 if (*s)
5714                         Con_Printf("invalid rtlights file \"%s\"\n", name);
5715                 Mem_Free(lightsstring);
5716         }
5717 }
5718
5719 void R_Shadow_SaveWorldLights(void)
5720 {
5721         size_t lightindex;
5722         dlight_t *light;
5723         size_t bufchars, bufmaxchars;
5724         char *buf, *oldbuf;
5725         char name[MAX_QPATH];
5726         char line[MAX_INPUTLINE];
5727         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5728         // I hate lines which are 3 times my screen size :( --blub
5729         if (!range)
5730                 return;
5731         if (cl.worldmodel == NULL)
5732         {
5733                 Con_Print("No map loaded.\n");
5734                 return;
5735         }
5736         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5737         bufchars = bufmaxchars = 0;
5738         buf = NULL;
5739         for (lightindex = 0;lightindex < range;lightindex++)
5740         {
5741                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5742                 if (!light)
5743                         continue;
5744                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5745                         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);
5746                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5747                         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]);
5748                 else
5749                         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);
5750                 if (bufchars + strlen(line) > bufmaxchars)
5751                 {
5752                         bufmaxchars = bufchars + strlen(line) + 2048;
5753                         oldbuf = buf;
5754                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5755                         if (oldbuf)
5756                         {
5757                                 if (bufchars)
5758                                         memcpy(buf, oldbuf, bufchars);
5759                                 Mem_Free(oldbuf);
5760                         }
5761                 }
5762                 if (strlen(line))
5763                 {
5764                         memcpy(buf + bufchars, line, strlen(line));
5765                         bufchars += strlen(line);
5766                 }
5767         }
5768         if (bufchars)
5769                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5770         if (buf)
5771                 Mem_Free(buf);
5772 }
5773
5774 void R_Shadow_LoadLightsFile(void)
5775 {
5776         int n, a, style;
5777         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5778         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5779         if (cl.worldmodel == NULL)
5780         {
5781                 Con_Print("No map loaded.\n");
5782                 return;
5783         }
5784         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5785         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5786         if (lightsstring)
5787         {
5788                 s = lightsstring;
5789                 n = 0;
5790                 while (*s)
5791                 {
5792                         t = s;
5793                         while (*s && *s != '\n' && *s != '\r')
5794                                 s++;
5795                         if (!*s)
5796                                 break;
5797                         tempchar = *s;
5798                         *s = 0;
5799                         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);
5800                         *s = tempchar;
5801                         if (a < 14)
5802                         {
5803                                 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);
5804                                 break;
5805                         }
5806                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5807                         radius = bound(15, radius, 4096);
5808                         VectorScale(color, (2.0f / (8388608.0f)), color);
5809                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5810                         if (*s == '\r')
5811                                 s++;
5812                         if (*s == '\n')
5813                                 s++;
5814                         n++;
5815                 }
5816                 if (*s)
5817                         Con_Printf("invalid lights file \"%s\"\n", name);
5818                 Mem_Free(lightsstring);
5819         }
5820 }
5821
5822 // tyrlite/hmap2 light types in the delay field
5823 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5824
5825 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5826 {
5827         int entnum;
5828         int style;
5829         int islight;
5830         int skin;
5831         int pflags;
5832         //int effects;
5833         int type;
5834         int n;
5835         char *entfiledata;
5836         const char *data;
5837         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5838         char key[256], value[MAX_INPUTLINE];
5839
5840         if (cl.worldmodel == NULL)
5841         {
5842                 Con_Print("No map loaded.\n");
5843                 return;
5844         }
5845         // try to load a .ent file first
5846         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5847         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5848         // and if that is not found, fall back to the bsp file entity string
5849         if (!data)
5850                 data = cl.worldmodel->brush.entities;
5851         if (!data)
5852                 return;
5853         for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5854         {
5855                 type = LIGHTTYPE_MINUSX;
5856                 origin[0] = origin[1] = origin[2] = 0;
5857                 originhack[0] = originhack[1] = originhack[2] = 0;
5858                 angles[0] = angles[1] = angles[2] = 0;
5859                 color[0] = color[1] = color[2] = 1;
5860                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5861                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5862                 fadescale = 1;
5863                 lightscale = 1;
5864                 style = 0;
5865                 skin = 0;
5866                 pflags = 0;
5867                 //effects = 0;
5868                 islight = false;
5869                 while (1)
5870                 {
5871                         if (!COM_ParseToken_Simple(&data, false, false))
5872                                 break; // error
5873                         if (com_token[0] == '}')
5874                                 break; // end of entity
5875                         if (com_token[0] == '_')
5876                                 strlcpy(key, com_token + 1, sizeof(key));
5877                         else
5878                                 strlcpy(key, com_token, sizeof(key));
5879                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5880                                 key[strlen(key)-1] = 0;
5881                         if (!COM_ParseToken_Simple(&data, false, false))
5882                                 break; // error
5883                         strlcpy(value, com_token, sizeof(value));
5884
5885                         // now that we have the key pair worked out...
5886                         if (!strcmp("light", key))
5887                         {
5888                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5889                                 if (n == 1)
5890                                 {
5891                                         // quake
5892                                         light[0] = vec[0] * (1.0f / 256.0f);
5893                                         light[1] = vec[0] * (1.0f / 256.0f);
5894                                         light[2] = vec[0] * (1.0f / 256.0f);
5895                                         light[3] = vec[0];
5896                                 }
5897                                 else if (n == 4)
5898                                 {
5899                                         // halflife
5900                                         light[0] = vec[0] * (1.0f / 255.0f);
5901                                         light[1] = vec[1] * (1.0f / 255.0f);
5902                                         light[2] = vec[2] * (1.0f / 255.0f);
5903                                         light[3] = vec[3];
5904                                 }
5905                         }
5906                         else if (!strcmp("delay", key))
5907                                 type = atoi(value);
5908                         else if (!strcmp("origin", key))
5909                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5910                         else if (!strcmp("angle", key))
5911                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5912                         else if (!strcmp("angles", key))
5913                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5914                         else if (!strcmp("color", key))
5915                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5916                         else if (!strcmp("wait", key))
5917                                 fadescale = atof(value);
5918                         else if (!strcmp("classname", key))
5919                         {
5920                                 if (!strncmp(value, "light", 5))
5921                                 {
5922                                         islight = true;
5923                                         if (!strcmp(value, "light_fluoro"))
5924                                         {
5925                                                 originhack[0] = 0;
5926                                                 originhack[1] = 0;
5927                                                 originhack[2] = 0;
5928                                                 overridecolor[0] = 1;
5929                                                 overridecolor[1] = 1;
5930                                                 overridecolor[2] = 1;
5931                                         }
5932                                         if (!strcmp(value, "light_fluorospark"))
5933                                         {
5934                                                 originhack[0] = 0;
5935                                                 originhack[1] = 0;
5936                                                 originhack[2] = 0;
5937                                                 overridecolor[0] = 1;
5938                                                 overridecolor[1] = 1;
5939                                                 overridecolor[2] = 1;
5940                                         }
5941                                         if (!strcmp(value, "light_globe"))
5942                                         {
5943                                                 originhack[0] = 0;
5944                                                 originhack[1] = 0;
5945                                                 originhack[2] = 0;
5946                                                 overridecolor[0] = 1;
5947                                                 overridecolor[1] = 0.8;
5948                                                 overridecolor[2] = 0.4;
5949                                         }
5950                                         if (!strcmp(value, "light_flame_large_yellow"))
5951                                         {
5952                                                 originhack[0] = 0;
5953                                                 originhack[1] = 0;
5954                                                 originhack[2] = 0;
5955                                                 overridecolor[0] = 1;
5956                                                 overridecolor[1] = 0.5;
5957                                                 overridecolor[2] = 0.1;
5958                                         }
5959                                         if (!strcmp(value, "light_flame_small_yellow"))
5960                                         {
5961                                                 originhack[0] = 0;
5962                                                 originhack[1] = 0;
5963                                                 originhack[2] = 0;
5964                                                 overridecolor[0] = 1;
5965                                                 overridecolor[1] = 0.5;
5966                                                 overridecolor[2] = 0.1;
5967                                         }
5968                                         if (!strcmp(value, "light_torch_small_white"))
5969                                         {
5970                                                 originhack[0] = 0;
5971                                                 originhack[1] = 0;
5972                                                 originhack[2] = 0;
5973                                                 overridecolor[0] = 1;
5974                                                 overridecolor[1] = 0.5;
5975                                                 overridecolor[2] = 0.1;
5976                                         }
5977                                         if (!strcmp(value, "light_torch_small_walltorch"))
5978                                         {
5979                                                 originhack[0] = 0;
5980                                                 originhack[1] = 0;
5981                                                 originhack[2] = 0;
5982                                                 overridecolor[0] = 1;
5983                                                 overridecolor[1] = 0.5;
5984                                                 overridecolor[2] = 0.1;
5985                                         }
5986                                 }
5987                         }
5988                         else if (!strcmp("style", key))
5989                                 style = atoi(value);
5990                         else if (!strcmp("skin", key))
5991                                 skin = (int)atof(value);
5992                         else if (!strcmp("pflags", key))
5993                                 pflags = (int)atof(value);
5994                         //else if (!strcmp("effects", key))
5995                         //      effects = (int)atof(value);
5996                         else if (cl.worldmodel->type == mod_brushq3)
5997                         {
5998                                 if (!strcmp("scale", key))
5999                                         lightscale = atof(value);
6000                                 if (!strcmp("fade", key))
6001                                         fadescale = atof(value);
6002                         }
6003                 }
6004                 if (!islight)
6005                         continue;
6006                 if (lightscale <= 0)
6007                         lightscale = 1;
6008                 if (fadescale <= 0)
6009                         fadescale = 1;
6010                 if (color[0] == color[1] && color[0] == color[2])
6011                 {
6012                         color[0] *= overridecolor[0];
6013                         color[1] *= overridecolor[1];
6014                         color[2] *= overridecolor[2];
6015                 }
6016                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6017                 color[0] = color[0] * light[0];
6018                 color[1] = color[1] * light[1];
6019                 color[2] = color[2] * light[2];
6020                 switch (type)
6021                 {
6022                 case LIGHTTYPE_MINUSX:
6023                         break;
6024                 case LIGHTTYPE_RECIPX:
6025                         radius *= 2;
6026                         VectorScale(color, (1.0f / 16.0f), color);
6027                         break;
6028                 case LIGHTTYPE_RECIPXX:
6029                         radius *= 2;
6030                         VectorScale(color, (1.0f / 16.0f), color);
6031                         break;
6032                 default:
6033                 case LIGHTTYPE_NONE:
6034                         break;
6035                 case LIGHTTYPE_SUN:
6036                         break;
6037                 case LIGHTTYPE_MINUSXX:
6038                         break;
6039                 }
6040                 VectorAdd(origin, originhack, origin);
6041                 if (radius >= 1)
6042                         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);
6043         }
6044         if (entfiledata)
6045                 Mem_Free(entfiledata);
6046 }
6047
6048
6049 void R_Shadow_SetCursorLocationForView(void)
6050 {
6051         vec_t dist, push;
6052         vec3_t dest, endpos;
6053         trace_t trace;
6054         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6055         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
6056         if (trace.fraction < 1)
6057         {
6058                 dist = trace.fraction * r_editlights_cursordistance.value;
6059                 push = r_editlights_cursorpushback.value;
6060                 if (push > dist)
6061                         push = dist;
6062                 push = -push;
6063                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6064                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6065         }
6066         else
6067         {
6068                 VectorClear( endpos );
6069         }
6070         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6071         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6072         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6073 }
6074
6075 void R_Shadow_UpdateWorldLightSelection(void)
6076 {
6077         if (r_editlights.integer)
6078         {
6079                 R_Shadow_SetCursorLocationForView();
6080                 R_Shadow_SelectLightInView();
6081         }
6082         else
6083                 R_Shadow_SelectLight(NULL);
6084 }
6085
6086 void R_Shadow_EditLights_Clear_f(void)
6087 {
6088         R_Shadow_ClearWorldLights();
6089 }
6090
6091 void R_Shadow_EditLights_Reload_f(void)
6092 {
6093         if (!cl.worldmodel)
6094                 return;
6095         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6096         R_Shadow_ClearWorldLights();
6097         R_Shadow_LoadWorldLights();
6098         if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6099         {
6100                 R_Shadow_LoadLightsFile();
6101                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6102                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6103         }
6104 }
6105
6106 void R_Shadow_EditLights_Save_f(void)
6107 {
6108         if (!cl.worldmodel)
6109                 return;
6110         R_Shadow_SaveWorldLights();
6111 }
6112
6113 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6114 {
6115         R_Shadow_ClearWorldLights();
6116         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6117 }
6118
6119 void R_Shadow_EditLights_ImportLightsFile_f(void)
6120 {
6121         R_Shadow_ClearWorldLights();
6122         R_Shadow_LoadLightsFile();
6123 }
6124
6125 void R_Shadow_EditLights_Spawn_f(void)
6126 {
6127         vec3_t color;
6128         if (!r_editlights.integer)
6129         {
6130                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6131                 return;
6132         }
6133         if (Cmd_Argc() != 1)
6134         {
6135                 Con_Print("r_editlights_spawn does not take parameters\n");
6136                 return;
6137         }
6138         color[0] = color[1] = color[2] = 1;
6139         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6140 }
6141
6142 void R_Shadow_EditLights_Edit_f(void)
6143 {
6144         vec3_t origin, angles, color;
6145         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6146         int style, shadows, flags, normalmode, realtimemode;
6147         char cubemapname[MAX_INPUTLINE];
6148         if (!r_editlights.integer)
6149         {
6150                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6151                 return;
6152         }
6153         if (!r_shadow_selectedlight)
6154         {
6155                 Con_Print("No selected light.\n");
6156                 return;
6157         }
6158         VectorCopy(r_shadow_selectedlight->origin, origin);
6159         VectorCopy(r_shadow_selectedlight->angles, angles);
6160         VectorCopy(r_shadow_selectedlight->color, color);
6161         radius = r_shadow_selectedlight->radius;
6162         style = r_shadow_selectedlight->style;
6163         if (r_shadow_selectedlight->cubemapname)
6164                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6165         else
6166                 cubemapname[0] = 0;
6167         shadows = r_shadow_selectedlight->shadow;
6168         corona = r_shadow_selectedlight->corona;
6169         coronasizescale = r_shadow_selectedlight->coronasizescale;
6170         ambientscale = r_shadow_selectedlight->ambientscale;
6171         diffusescale = r_shadow_selectedlight->diffusescale;
6172         specularscale = r_shadow_selectedlight->specularscale;
6173         flags = r_shadow_selectedlight->flags;
6174         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6175         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6176         if (!strcmp(Cmd_Argv(1), "origin"))
6177         {
6178                 if (Cmd_Argc() != 5)
6179                 {
6180                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6181                         return;
6182                 }
6183                 origin[0] = atof(Cmd_Argv(2));
6184                 origin[1] = atof(Cmd_Argv(3));
6185                 origin[2] = atof(Cmd_Argv(4));
6186         }
6187         else if (!strcmp(Cmd_Argv(1), "originscale"))
6188         {
6189                 if (Cmd_Argc() != 5)
6190                 {
6191                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6192                         return;
6193                 }
6194                 origin[0] *= atof(Cmd_Argv(2));
6195                 origin[1] *= atof(Cmd_Argv(3));
6196                 origin[2] *= atof(Cmd_Argv(4));
6197         }
6198         else if (!strcmp(Cmd_Argv(1), "originx"))
6199         {
6200                 if (Cmd_Argc() != 3)
6201                 {
6202                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6203                         return;
6204                 }
6205                 origin[0] = atof(Cmd_Argv(2));
6206         }
6207         else if (!strcmp(Cmd_Argv(1), "originy"))
6208         {
6209                 if (Cmd_Argc() != 3)
6210                 {
6211                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6212                         return;
6213                 }
6214                 origin[1] = atof(Cmd_Argv(2));
6215         }
6216         else if (!strcmp(Cmd_Argv(1), "originz"))
6217         {
6218                 if (Cmd_Argc() != 3)
6219                 {
6220                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6221                         return;
6222                 }
6223                 origin[2] = atof(Cmd_Argv(2));
6224         }
6225         else if (!strcmp(Cmd_Argv(1), "move"))
6226         {
6227                 if (Cmd_Argc() != 5)
6228                 {
6229                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6230                         return;
6231                 }
6232                 origin[0] += atof(Cmd_Argv(2));
6233                 origin[1] += atof(Cmd_Argv(3));
6234                 origin[2] += atof(Cmd_Argv(4));
6235         }
6236         else if (!strcmp(Cmd_Argv(1), "movex"))
6237         {
6238                 if (Cmd_Argc() != 3)
6239                 {
6240                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6241                         return;
6242                 }
6243                 origin[0] += atof(Cmd_Argv(2));
6244         }
6245         else if (!strcmp(Cmd_Argv(1), "movey"))
6246         {
6247                 if (Cmd_Argc() != 3)
6248                 {
6249                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6250                         return;
6251                 }
6252                 origin[1] += atof(Cmd_Argv(2));
6253         }
6254         else if (!strcmp(Cmd_Argv(1), "movez"))
6255         {
6256                 if (Cmd_Argc() != 3)
6257                 {
6258                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6259                         return;
6260                 }
6261                 origin[2] += atof(Cmd_Argv(2));
6262         }
6263         else if (!strcmp(Cmd_Argv(1), "angles"))
6264         {
6265                 if (Cmd_Argc() != 5)
6266                 {
6267                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6268                         return;
6269                 }
6270                 angles[0] = atof(Cmd_Argv(2));
6271                 angles[1] = atof(Cmd_Argv(3));
6272                 angles[2] = atof(Cmd_Argv(4));
6273         }
6274         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6275         {
6276                 if (Cmd_Argc() != 3)
6277                 {
6278                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6279                         return;
6280                 }
6281                 angles[0] = atof(Cmd_Argv(2));
6282         }
6283         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6284         {
6285                 if (Cmd_Argc() != 3)
6286                 {
6287                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6288                         return;
6289                 }
6290                 angles[1] = atof(Cmd_Argv(2));
6291         }
6292         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6293         {
6294                 if (Cmd_Argc() != 3)
6295                 {
6296                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6297                         return;
6298                 }
6299                 angles[2] = atof(Cmd_Argv(2));
6300         }
6301         else if (!strcmp(Cmd_Argv(1), "color"))
6302         {
6303                 if (Cmd_Argc() != 5)
6304                 {
6305                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6306                         return;
6307                 }
6308                 color[0] = atof(Cmd_Argv(2));
6309                 color[1] = atof(Cmd_Argv(3));
6310                 color[2] = atof(Cmd_Argv(4));
6311         }
6312         else if (!strcmp(Cmd_Argv(1), "radius"))
6313         {
6314                 if (Cmd_Argc() != 3)
6315                 {
6316                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6317                         return;
6318                 }
6319                 radius = atof(Cmd_Argv(2));
6320         }
6321         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6322         {
6323                 if (Cmd_Argc() == 3)
6324                 {
6325                         double scale = atof(Cmd_Argv(2));
6326                         color[0] *= scale;
6327                         color[1] *= scale;
6328                         color[2] *= scale;
6329                 }
6330                 else
6331                 {
6332                         if (Cmd_Argc() != 5)
6333                         {
6334                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
6335                                 return;
6336                         }
6337                         color[0] *= atof(Cmd_Argv(2));
6338                         color[1] *= atof(Cmd_Argv(3));
6339                         color[2] *= atof(Cmd_Argv(4));
6340                 }
6341         }
6342         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6343         {
6344                 if (Cmd_Argc() != 3)
6345                 {
6346                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6347                         return;
6348                 }
6349                 radius *= atof(Cmd_Argv(2));
6350         }
6351         else if (!strcmp(Cmd_Argv(1), "style"))
6352         {
6353                 if (Cmd_Argc() != 3)
6354                 {
6355                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6356                         return;
6357                 }
6358                 style = atoi(Cmd_Argv(2));
6359         }
6360         else if (!strcmp(Cmd_Argv(1), "cubemap"))
6361         {
6362                 if (Cmd_Argc() > 3)
6363                 {
6364                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6365                         return;
6366                 }
6367                 if (Cmd_Argc() == 3)
6368                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6369                 else
6370                         cubemapname[0] = 0;
6371         }
6372         else if (!strcmp(Cmd_Argv(1), "shadows"))
6373         {
6374                 if (Cmd_Argc() != 3)
6375                 {
6376                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6377                         return;
6378                 }
6379                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6380         }
6381         else if (!strcmp(Cmd_Argv(1), "corona"))
6382         {
6383                 if (Cmd_Argc() != 3)
6384                 {
6385                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6386                         return;
6387                 }
6388                 corona = atof(Cmd_Argv(2));
6389         }
6390         else if (!strcmp(Cmd_Argv(1), "coronasize"))
6391         {
6392                 if (Cmd_Argc() != 3)
6393                 {
6394                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6395                         return;
6396                 }
6397                 coronasizescale = atof(Cmd_Argv(2));
6398         }
6399         else if (!strcmp(Cmd_Argv(1), "ambient"))
6400         {
6401                 if (Cmd_Argc() != 3)
6402                 {
6403                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6404                         return;
6405                 }
6406                 ambientscale = atof(Cmd_Argv(2));
6407         }
6408         else if (!strcmp(Cmd_Argv(1), "diffuse"))
6409         {
6410                 if (Cmd_Argc() != 3)
6411                 {
6412                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6413                         return;
6414                 }
6415                 diffusescale = atof(Cmd_Argv(2));
6416         }
6417         else if (!strcmp(Cmd_Argv(1), "specular"))
6418         {
6419                 if (Cmd_Argc() != 3)
6420                 {
6421                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6422                         return;
6423                 }
6424                 specularscale = atof(Cmd_Argv(2));
6425         }
6426         else if (!strcmp(Cmd_Argv(1), "normalmode"))
6427         {
6428                 if (Cmd_Argc() != 3)
6429                 {
6430                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6431                         return;
6432                 }
6433                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6434         }
6435         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6436         {
6437                 if (Cmd_Argc() != 3)
6438                 {
6439                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6440                         return;
6441                 }
6442                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6443         }
6444         else
6445         {
6446                 Con_Print("usage: r_editlights_edit [property] [value]\n");
6447                 Con_Print("Selected light's properties:\n");
6448                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6449                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6450                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6451                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
6452                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
6453                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
6454                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6455                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
6456                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
6457                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
6458                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
6459                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
6460                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6461                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6462                 return;
6463         }
6464         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6465         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6466 }
6467
6468 void R_Shadow_EditLights_EditAll_f(void)
6469 {
6470         size_t lightindex;
6471         dlight_t *light, *oldselected;
6472         size_t range;
6473
6474         if (!r_editlights.integer)
6475         {
6476                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6477                 return;
6478         }
6479
6480         oldselected = r_shadow_selectedlight;
6481         // EditLights doesn't seem to have a "remove" command or something so:
6482         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6483         for (lightindex = 0;lightindex < range;lightindex++)
6484         {
6485                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6486                 if (!light)
6487                         continue;
6488                 R_Shadow_SelectLight(light);
6489                 R_Shadow_EditLights_Edit_f();
6490         }
6491         // return to old selected (to not mess editing once selection is locked)
6492         R_Shadow_SelectLight(oldselected);
6493 }
6494
6495 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6496 {
6497         int lightnumber, lightcount;
6498         size_t lightindex, range;
6499         dlight_t *light;
6500         float x, y;
6501         char temp[256];
6502         if (!r_editlights.integer)
6503                 return;
6504         x = vid_conwidth.value - 240;
6505         y = 5;
6506         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6507         lightnumber = -1;
6508         lightcount = 0;
6509         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6510         for (lightindex = 0;lightindex < range;lightindex++)
6511         {
6512                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6513                 if (!light)
6514                         continue;
6515                 if (light == r_shadow_selectedlight)
6516                         lightnumber = lightindex;
6517                 lightcount++;
6518         }
6519         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;
6520         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;
6521         y += 8;
6522         if (r_shadow_selectedlight == NULL)
6523                 return;
6524         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;
6525         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;
6526         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;
6527         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;
6528         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;
6529         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;
6530         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;
6531         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;
6532         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;
6533         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;
6534         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;
6535         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;
6536         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;
6537         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;
6538         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;
6539 }
6540
6541 void R_Shadow_EditLights_ToggleShadow_f(void)
6542 {
6543         if (!r_editlights.integer)
6544         {
6545                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6546                 return;
6547         }
6548         if (!r_shadow_selectedlight)
6549         {
6550                 Con_Print("No selected light.\n");
6551                 return;
6552         }
6553         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);
6554 }
6555
6556 void R_Shadow_EditLights_ToggleCorona_f(void)
6557 {
6558         if (!r_editlights.integer)
6559         {
6560                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6561                 return;
6562         }
6563         if (!r_shadow_selectedlight)
6564         {
6565                 Con_Print("No selected light.\n");
6566                 return;
6567         }
6568         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);
6569 }
6570
6571 void R_Shadow_EditLights_Remove_f(void)
6572 {
6573         if (!r_editlights.integer)
6574         {
6575                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
6576                 return;
6577         }
6578         if (!r_shadow_selectedlight)
6579         {
6580                 Con_Print("No selected light.\n");
6581                 return;
6582         }
6583         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6584         r_shadow_selectedlight = NULL;
6585 }
6586
6587 void R_Shadow_EditLights_Help_f(void)
6588 {
6589         Con_Print(
6590 "Documentation on r_editlights system:\n"
6591 "Settings:\n"
6592 "r_editlights : enable/disable editing mode\n"
6593 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6594 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6595 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6596 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6597 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6598 "Commands:\n"
6599 "r_editlights_help : this help\n"
6600 "r_editlights_clear : remove all lights\n"
6601 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6602 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6603 "r_editlights_save : save to .rtlights file\n"
6604 "r_editlights_spawn : create a light with default settings\n"
6605 "r_editlights_edit command : edit selected light - more documentation below\n"
6606 "r_editlights_remove : remove selected light\n"
6607 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6608 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6609 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6610 "Edit commands:\n"
6611 "origin x y z : set light location\n"
6612 "originx x: set x component of light location\n"
6613 "originy y: set y component of light location\n"
6614 "originz z: set z component of light location\n"
6615 "move x y z : adjust light location\n"
6616 "movex x: adjust x component of light location\n"
6617 "movey y: adjust y component of light location\n"
6618 "movez z: adjust z component of light location\n"
6619 "angles x y z : set light angles\n"
6620 "anglesx x: set x component of light angles\n"
6621 "anglesy y: set y component of light angles\n"
6622 "anglesz z: set z component of light angles\n"
6623 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6624 "radius radius : set radius (size) of light\n"
6625 "colorscale grey : multiply color of light (1 does nothing)\n"
6626 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6627 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6628 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6629 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6630 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6631 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6632 "shadows 1/0 : turn on/off shadows\n"
6633 "corona n : set corona intensity\n"
6634 "coronasize n : set corona size (0-1)\n"
6635 "ambient n : set ambient intensity (0-1)\n"
6636 "diffuse n : set diffuse intensity (0-1)\n"
6637 "specular n : set specular intensity (0-1)\n"
6638 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6639 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6640 "<nothing> : print light properties to console\n"
6641         );
6642 }
6643
6644 void R_Shadow_EditLights_CopyInfo_f(void)
6645 {
6646         if (!r_editlights.integer)
6647         {
6648                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
6649                 return;
6650         }
6651         if (!r_shadow_selectedlight)
6652         {
6653                 Con_Print("No selected light.\n");
6654                 return;
6655         }
6656         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6657         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6658         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6659         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6660         if (r_shadow_selectedlight->cubemapname)
6661                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6662         else
6663                 r_shadow_bufferlight.cubemapname[0] = 0;
6664         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6665         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6666         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6667         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6668         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6669         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6670         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6671 }
6672
6673 void R_Shadow_EditLights_PasteInfo_f(void)
6674 {
6675         if (!r_editlights.integer)
6676         {
6677                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
6678                 return;
6679         }
6680         if (!r_shadow_selectedlight)
6681         {
6682                 Con_Print("No selected light.\n");
6683                 return;
6684         }
6685         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);
6686 }
6687
6688 void R_Shadow_EditLights_Lock_f(void)
6689 {
6690         if (!r_editlights.integer)
6691         {
6692                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
6693                 return;
6694         }
6695         if (r_editlights_lockcursor)
6696         {
6697                 r_editlights_lockcursor = false;
6698                 return;
6699         }
6700         if (!r_shadow_selectedlight)
6701         {
6702                 Con_Print("No selected light to lock on.\n");
6703                 return;
6704         }
6705         r_editlights_lockcursor = true;
6706 }
6707
6708 void R_Shadow_EditLights_Init(void)
6709 {
6710         Cvar_RegisterVariable(&r_editlights);
6711         Cvar_RegisterVariable(&r_editlights_cursordistance);
6712         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6713         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6714         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6715         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6716         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6717         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6718         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)");
6719         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6720         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6721         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6722         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)");
6723         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6724         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6725         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6726         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6727         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6728         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6729         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)");
6730         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6731 }
6732
6733
6734
6735 /*
6736 =============================================================================
6737
6738 LIGHT SAMPLING
6739
6740 =============================================================================
6741 */
6742
6743 void R_LightPoint(vec3_t color, const vec3_t p, const int flags)
6744 {
6745         int i, numlights, flag;
6746         float f, relativepoint[3], dist, dist2, lightradius2;
6747         vec3_t diffuse, n;
6748         rtlight_t *light;
6749         dlight_t *dlight;
6750
6751         VectorClear(color);
6752
6753         if (r_fullbright.integer)
6754         {
6755                 VectorSet(color, 1, 1, 1);
6756                 return;
6757         }
6758
6759         if (flags & LP_LIGHTMAP)
6760         {
6761                 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6762                 {
6763                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6764                         color[0] += r_refdef.scene.ambient + diffuse[0];
6765                         color[1] += r_refdef.scene.ambient + diffuse[1];
6766                         color[2] += r_refdef.scene.ambient + diffuse[2];
6767                 }
6768                 else
6769                         VectorSet(color, 1, 1, 1);
6770         }
6771         if (flags & LP_RTWORLD)
6772         {
6773                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6774                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6775                 for (i = 0; i < numlights; i++)
6776                 {
6777                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6778                         if (!dlight)
6779                                 continue;
6780                         light = &dlight->rtlight;
6781                         if (!(light->flags & flag))
6782                                 continue;
6783                         // sample
6784                         lightradius2 = light->radius * light->radius;
6785                         VectorSubtract(light->shadoworigin, p, relativepoint);
6786                         dist2 = VectorLength2(relativepoint);
6787                         if (dist2 >= lightradius2)
6788                                 continue;
6789                         dist = sqrt(dist2) / light->radius;
6790                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6791                         if (f <= 0)
6792                                 continue;
6793                         // todo: add to both ambient and diffuse
6794                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6795                                 VectorMA(color, f, light->currentcolor, color);
6796                 }
6797         }
6798         if (flags & LP_DYNLIGHT)
6799         {
6800                 // sample dlights
6801                 for (i = 0;i < r_refdef.scene.numlights;i++)
6802                 {
6803                         light = r_refdef.scene.lights[i];
6804                         // sample
6805                         lightradius2 = light->radius * light->radius;
6806                         VectorSubtract(light->shadoworigin, p, relativepoint);
6807                         dist2 = VectorLength2(relativepoint);
6808                         if (dist2 >= lightradius2)
6809                                 continue;
6810                         dist = sqrt(dist2) / light->radius;
6811                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6812                         if (f <= 0)
6813                                 continue;
6814                         // todo: add to both ambient and diffuse
6815                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
6816                                 VectorMA(color, f, light->color, color);
6817                 }
6818         }
6819 }
6820
6821 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6822 {
6823         int i, numlights, flag;
6824         rtlight_t *light;
6825         dlight_t *dlight;
6826         float relativepoint[3];
6827         float color[3];
6828         float dir[3];
6829         float dist;
6830         float dist2;
6831         float intensity;
6832         float sample[5*3];
6833         float lightradius2;
6834
6835         if (r_fullbright.integer)
6836         {
6837                 VectorSet(ambient, 1, 1, 1);
6838                 VectorClear(diffuse);
6839                 VectorClear(lightdir);
6840                 return;
6841         }
6842
6843         if (flags == LP_LIGHTMAP)
6844         {
6845                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6846                 VectorClear(diffuse);
6847                 VectorClear(lightdir);
6848                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6849                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6850                 return;
6851         }
6852
6853         memset(sample, 0, sizeof(sample));
6854         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6855
6856         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6857         {
6858                 vec3_t tempambient;
6859                 VectorClear(tempambient);
6860                 VectorClear(color);
6861                 VectorClear(relativepoint);
6862                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6863                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6864                 VectorScale(color, r_refdef.lightmapintensity, color);
6865                 VectorAdd(sample, tempambient, sample);
6866                 VectorMA(sample    , 0.5f            , color, sample    );
6867                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6868                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6869                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6870                 // calculate a weighted average light direction as well
6871                 intensity = VectorLength(color);
6872                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6873         }
6874
6875         if (flags & LP_RTWORLD)
6876         {
6877                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6878                 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6879                 for (i = 0; i < numlights; i++)
6880                 {
6881                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6882                         if (!dlight)
6883                                 continue;
6884                         light = &dlight->rtlight;
6885                         if (!(light->flags & flag))
6886                                 continue;
6887                         // sample
6888                         lightradius2 = light->radius * light->radius;
6889                         VectorSubtract(light->shadoworigin, p, relativepoint);
6890                         dist2 = VectorLength2(relativepoint);
6891                         if (dist2 >= lightradius2)
6892                                 continue;
6893                         dist = sqrt(dist2) / light->radius;
6894                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6895                         if (intensity <= 0.0f)
6896                                 continue;
6897                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6898                                 continue;
6899                         // scale down intensity to add to both ambient and diffuse
6900                         //intensity *= 0.5f;
6901                         VectorNormalize(relativepoint);
6902                         VectorScale(light->currentcolor, intensity, color);
6903                         VectorMA(sample    , 0.5f            , color, sample    );
6904                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6905                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6906                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6907                         // calculate a weighted average light direction as well
6908                         intensity *= VectorLength(color);
6909                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6910                 }
6911         }
6912
6913         if (flags & LP_DYNLIGHT)
6914         {
6915                 // sample dlights
6916                 for (i = 0;i < r_refdef.scene.numlights;i++)
6917                 {
6918                         light = r_refdef.scene.lights[i];
6919                         // sample
6920                         lightradius2 = light->radius * light->radius;
6921                         VectorSubtract(light->shadoworigin, p, relativepoint);
6922                         dist2 = VectorLength2(relativepoint);
6923                         if (dist2 >= lightradius2)
6924                                 continue;
6925                         dist = sqrt(dist2) / light->radius;
6926                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6927                         if (intensity <= 0.0f)
6928                                 continue;
6929                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6930                                 continue;
6931                         // scale down intensity to add to both ambient and diffuse
6932                         //intensity *= 0.5f;
6933                         VectorNormalize(relativepoint);
6934                         VectorScale(light->currentcolor, intensity, color);
6935                         VectorMA(sample    , 0.5f            , color, sample    );
6936                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6937                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6938                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6939                         // calculate a weighted average light direction as well
6940                         intensity *= VectorLength(color);
6941                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6942                 }
6943         }
6944
6945         // calculate the direction we'll use to reduce the sample to a directional light source
6946         VectorCopy(sample + 12, dir);
6947         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6948         VectorNormalize(dir);
6949         // extract the diffuse color along the chosen direction and scale it
6950         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6951         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6952         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6953         // subtract some of diffuse from ambient
6954         VectorMA(sample, -0.333f, diffuse, ambient);
6955         // store the normalized lightdir
6956         VectorCopy(dir, lightdir);
6957 }