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