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