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