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