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