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