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