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