]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Fix infinite loop that occurred in R_FrameData_Alloc if requesting > 256MB (which...
[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 skipsupercontentsmask;
3130         int maxbounce;
3131         int shootparticles;
3132         int shotparticles;
3133         trace_t cliptrace;
3134         //trace_t cliptrace2;
3135         //trace_t cliptrace3;
3136         unsigned int lightindex;
3137         unsigned int seed = (unsigned int)(realtime * 1000.0f);
3138         vec3_t shotcolor;
3139         vec3_t baseshotcolor;
3140         vec3_t surfcolor;
3141         vec3_t clipend;
3142         vec3_t clipstart;
3143         vec3_t clipdiff;
3144         vec_t radius;
3145         vec_t s;
3146         rtlight_t *rtlight;
3147
3148         // we'll need somewhere to store these
3149         r_shadow_bouncegrid_state.numsplatpaths = 0;
3150         r_shadow_bouncegrid_state.splatpaths = (r_shadow_bouncegrid_splatpath_t *)R_FrameData_Alloc(sizeof(r_shadow_bouncegrid_splatpath_t) * r_shadow_bouncegrid_state.maxsplatpaths);
3151
3152         // figure out what we want to interact with
3153         if (settings.hitmodels)
3154                 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
3155         else
3156                 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
3157         skipsupercontentsmask = SUPERCONTENTS_SKY; // this allows the e1m5 sky shadow to work by ignoring the sky surfaces
3158         maxbounce = settings.maxbounce;
3159
3160         for (lightindex = 0;lightindex < range2;lightindex++)
3161         {
3162                 if (lightindex < range)
3163                 {
3164                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3165                         if (!light)
3166                                 continue;
3167                         rtlight = &light->rtlight;
3168                 }
3169                 else
3170                         rtlight = r_refdef.scene.lights[lightindex - range];
3171                 // note that this code used to keep track of residual photons and
3172                 // distribute them evenly to achieve exactly a desired photon count,
3173                 // but that caused unwanted flickering in dynamic mode
3174                 shootparticles = (int)floor(rtlight->photons * photonscaling);
3175                 // skip if we won't be shooting any photons
3176                 if (!shootparticles)
3177                         continue;
3178                 radius = rtlight->radius * settings.lightradiusscale;
3179                 s = settings.particleintensity / shootparticles;
3180                 VectorScale(rtlight->photoncolor, s, baseshotcolor);
3181                 r_refdef.stats[r_stat_bouncegrid_lights]++;
3182                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
3183                 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
3184                 {
3185                         if (settings.stablerandom > 0)
3186                                 seed = lightindex * 11937 + shotparticles;
3187                         VectorCopy(baseshotcolor, shotcolor);
3188                         VectorCopy(rtlight->shadoworigin, clipstart);
3189                         if (settings.stablerandom < 0)
3190                                 VectorRandom(clipend);
3191                         else
3192                                 VectorCheeseRandom(clipend);
3193                         VectorMA(clipstart, radius, clipend, clipend);
3194                         for (bouncecount = 0;;bouncecount++)
3195                         {
3196                                 r_refdef.stats[r_stat_bouncegrid_traces]++;
3197                                 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
3198                                 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
3199                                 if (settings.staticmode)
3200                                 {
3201                                         // static mode fires a LOT of rays but none of them are identical, so they are not cached
3202                                         cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, skipsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
3203                                 }
3204                                 else
3205                                 {
3206                                         // dynamic mode fires many rays and most will match the cache from the previous frame
3207                                         cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask, skipsupercontentsmask);
3208                                 }
3209                                 if (bouncecount > 0 || settings.includedirectlighting)
3210                                 {
3211                                         vec3_t hitpos;
3212                                         VectorCopy(cliptrace.endpos, hitpos);
3213                                         R_Shadow_BounceGrid_AddSplatPath(clipstart, hitpos, shotcolor);
3214                                 }
3215                                 if (cliptrace.fraction >= 1.0f)
3216                                         break;
3217                                 r_refdef.stats[r_stat_bouncegrid_hits]++;
3218                                 if (bouncecount >= maxbounce)
3219                                         break;
3220                                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
3221                                 // also clamp the resulting color to never add energy, even if the user requests extreme values
3222                                 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
3223                                         VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
3224                                 else
3225                                         VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
3226                                 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
3227                                 surfcolor[0] = min(surfcolor[0], 1.0f);
3228                                 surfcolor[1] = min(surfcolor[1], 1.0f);
3229                                 surfcolor[2] = min(surfcolor[2], 1.0f);
3230                                 VectorMultiply(shotcolor, surfcolor, shotcolor);
3231                                 if (VectorLength2(baseshotcolor) == 0.0f)
3232                                         break;
3233                                 r_refdef.stats[r_stat_bouncegrid_bounces]++;
3234                                 if (settings.bounceanglediffuse)
3235                                 {
3236                                         // random direction, primarily along plane normal
3237                                         s = VectorDistance(cliptrace.endpos, clipend);
3238                                         if (settings.stablerandom < 0)
3239                                                 VectorRandom(clipend);
3240                                         else
3241                                                 VectorCheeseRandom(clipend);
3242                                         VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
3243                                         VectorNormalize(clipend);
3244                                         VectorScale(clipend, s, clipend);
3245                                 }
3246                                 else
3247                                 {
3248                                         // reflect the remaining portion of the line across plane normal
3249                                         VectorSubtract(clipend, cliptrace.endpos, clipdiff);
3250                                         VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
3251                                 }
3252                                 // calculate the new line start and end
3253                                 VectorCopy(cliptrace.endpos, clipstart);
3254                                 VectorAdd(clipstart, clipend, clipend);
3255                         }
3256                 }
3257         }
3258 }
3259
3260 void R_Shadow_UpdateBounceGridTexture(void)
3261 {
3262         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3263         r_shadow_bouncegrid_settings_t settings;
3264         qboolean enable = false;
3265         qboolean settingschanged;
3266         unsigned int range; // number of world lights
3267         unsigned int range1; // number of dynamic lights (or zero if disabled)
3268         unsigned int range2; // range+range1
3269         float photonscaling;
3270
3271         enable = R_Shadow_BounceGrid_CheckEnable(flag);
3272         
3273         R_Shadow_BounceGrid_GenerateSettings(&settings);
3274         
3275         // changing intensity does not require an update
3276         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
3277
3278         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
3279
3280         // when settings change, we free everything as it is just simpler that way.
3281         if (settingschanged || !enable)
3282         {
3283                 // not enabled, make sure we free anything we don't need anymore.
3284                 if (r_shadow_bouncegrid_state.texture)
3285                 {
3286                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
3287                         r_shadow_bouncegrid_state.texture = NULL;
3288                 }
3289                 r_shadow_bouncegrid_state.numpixels = 0;
3290                 r_shadow_bouncegrid_state.directional = false;
3291
3292                 if (!enable)
3293                         return;
3294         }
3295
3296         // if all the settings seem identical to the previous update, return
3297         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
3298                 return;
3299
3300         // store the new settings
3301         r_shadow_bouncegrid_state.settings = settings;
3302
3303         R_Shadow_BounceGrid_UpdateSpacing();
3304
3305         // get the range of light numbers we'll be looping over:
3306         // range = static lights
3307         // range1 = dynamic lights (optional)
3308         // range2 = range + range1
3309         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3310         range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
3311         range2 = range + range1;
3312
3313         // calculate weighting factors for distributing photons among the lights
3314         R_Shadow_BounceGrid_AssignPhotons(&settings, range, range1, range2, flag, &photonscaling);
3315
3316         // trace the photons from lights and accumulate illumination
3317         R_Shadow_BounceGrid_TracePhotons(settings, range, range1, range2, photonscaling, flag);
3318
3319         // clear the texture
3320         R_Shadow_BounceGrid_ClearPixels();
3321         
3322         // accumulate the light splatting into texture
3323         R_Shadow_BounceGrid_PerformSplats();
3324
3325         // apply a mild blur filter to the texture
3326         R_Shadow_BounceGrid_BlurPixels();
3327
3328         // convert the pixels to lower precision and upload the texture
3329         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
3330 }
3331
3332 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
3333 {
3334         R_Shadow_RenderMode_Reset();
3335         GL_BlendFunc(GL_ONE, GL_ONE);
3336         GL_DepthRange(0, 1);
3337         GL_DepthTest(r_showshadowvolumes.integer < 2);
3338         GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
3339         GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
3340         GL_CullFace(GL_NONE);
3341         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
3342 }
3343
3344 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
3345 {
3346         R_Shadow_RenderMode_Reset();
3347         GL_BlendFunc(GL_ONE, GL_ONE);
3348         GL_DepthRange(0, 1);
3349         GL_DepthTest(r_showlighting.integer < 2);
3350         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
3351         if (!transparent)
3352                 GL_DepthFunc(GL_EQUAL);
3353         R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
3354         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
3355 }
3356
3357 void R_Shadow_RenderMode_End(void)
3358 {
3359         R_Shadow_RenderMode_Reset();
3360         R_Shadow_RenderMode_ActiveLight(NULL);
3361         GL_DepthMask(true);
3362         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3363         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
3364 }
3365
3366 int bboxedges[12][2] =
3367 {
3368         // top
3369         {0, 1}, // +X
3370         {0, 2}, // +Y
3371         {1, 3}, // Y, +X
3372         {2, 3}, // X, +Y
3373         // bottom
3374         {4, 5}, // +X
3375         {4, 6}, // +Y
3376         {5, 7}, // Y, +X
3377         {6, 7}, // X, +Y
3378         // verticals
3379         {0, 4}, // +Z
3380         {1, 5}, // X, +Z
3381         {2, 6}, // Y, +Z
3382         {3, 7}, // XY, +Z
3383 };
3384
3385 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
3386 {
3387         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
3388         {
3389                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
3390                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
3391                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
3392                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3393                 return false;
3394         }
3395         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3396                 return true; // invisible
3397         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3398         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3399         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3400         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3401                 r_refdef.stats[r_stat_lights_scissored]++;
3402         return false;
3403 }
3404
3405 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3406 {
3407         int i;
3408         const float *vertex3f;
3409         const float *normal3f;
3410         float *color4f;
3411         float dist, dot, distintensity, shadeintensity, v[3], n[3];
3412         switch (r_shadow_rendermode)
3413         {
3414         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3415         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3416                 if (VectorLength2(diffusecolor) > 0)
3417                 {
3418                         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)
3419                         {
3420                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3421                                 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3422                                 if ((dot = DotProduct(n, v)) < 0)
3423                                 {
3424                                         shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3425                                         VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3426                                 }
3427                                 else
3428                                         VectorCopy(ambientcolor, color4f);
3429                                 if (r_refdef.fogenabled)
3430                                 {
3431                                         float f;
3432                                         f = RSurf_FogVertex(vertex3f);
3433                                         VectorScale(color4f, f, color4f);
3434                                 }
3435                                 color4f[3] = 1;
3436                         }
3437                 }
3438                 else
3439                 {
3440                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3441                         {
3442                                 VectorCopy(ambientcolor, color4f);
3443                                 if (r_refdef.fogenabled)
3444                                 {
3445                                         float f;
3446                                         Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3447                                         f = RSurf_FogVertex(vertex3f);
3448                                         VectorScale(color4f + 4*i, f, color4f);
3449                                 }
3450                                 color4f[3] = 1;
3451                         }
3452                 }
3453                 break;
3454         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3455                 if (VectorLength2(diffusecolor) > 0)
3456                 {
3457                         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)
3458                         {
3459                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3460                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3461                                 {
3462                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3463                                         if ((dot = DotProduct(n, v)) < 0)
3464                                         {
3465                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3466                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3467                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3468                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3469                                         }
3470                                         else
3471                                         {
3472                                                 color4f[0] = ambientcolor[0] * distintensity;
3473                                                 color4f[1] = ambientcolor[1] * distintensity;
3474                                                 color4f[2] = ambientcolor[2] * distintensity;
3475                                         }
3476                                         if (r_refdef.fogenabled)
3477                                         {
3478                                                 float f;
3479                                                 f = RSurf_FogVertex(vertex3f);
3480                                                 VectorScale(color4f, f, color4f);
3481                                         }
3482                                 }
3483                                 else
3484                                         VectorClear(color4f);
3485                                 color4f[3] = 1;
3486                         }
3487                 }
3488                 else
3489                 {
3490                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3491                         {
3492                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3493                                 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3494                                 {
3495                                         color4f[0] = ambientcolor[0] * distintensity;
3496                                         color4f[1] = ambientcolor[1] * distintensity;
3497                                         color4f[2] = ambientcolor[2] * distintensity;
3498                                         if (r_refdef.fogenabled)
3499                                         {
3500                                                 float f;
3501                                                 f = RSurf_FogVertex(vertex3f);
3502                                                 VectorScale(color4f, f, color4f);
3503                                         }
3504                                 }
3505                                 else
3506                                         VectorClear(color4f);
3507                                 color4f[3] = 1;
3508                         }
3509                 }
3510                 break;
3511         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3512                 if (VectorLength2(diffusecolor) > 0)
3513                 {
3514                         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)
3515                         {
3516                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3517                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3518                                 {
3519                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3520                                         Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3521                                         if ((dot = DotProduct(n, v)) < 0)
3522                                         {
3523                                                 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3524                                                 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3525                                                 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3526                                                 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3527                                         }
3528                                         else
3529                                         {
3530                                                 color4f[0] = ambientcolor[0] * distintensity;
3531                                                 color4f[1] = ambientcolor[1] * distintensity;
3532                                                 color4f[2] = ambientcolor[2] * distintensity;
3533                                         }
3534                                         if (r_refdef.fogenabled)
3535                                         {
3536                                                 float f;
3537                                                 f = RSurf_FogVertex(vertex3f);
3538                                                 VectorScale(color4f, f, color4f);
3539                                         }
3540                                 }
3541                                 else
3542                                         VectorClear(color4f);
3543                                 color4f[3] = 1;
3544                         }
3545                 }
3546                 else
3547                 {
3548                         for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3549                         {
3550                                 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3551                                 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3552                                 {
3553                                         distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3554                                         color4f[0] = ambientcolor[0] * distintensity;
3555                                         color4f[1] = ambientcolor[1] * distintensity;
3556                                         color4f[2] = ambientcolor[2] * distintensity;
3557                                         if (r_refdef.fogenabled)
3558                                         {
3559                                                 float f;
3560                                                 f = RSurf_FogVertex(vertex3f);
3561                                                 VectorScale(color4f, f, color4f);
3562                                         }
3563                                 }
3564                                 else
3565                                         VectorClear(color4f);
3566                                 color4f[3] = 1;
3567                         }
3568                 }
3569                 break;
3570         default:
3571                 break;
3572         }
3573 }
3574
3575 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3576 {
3577         // used to display how many times a surface is lit for level design purposes
3578         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3579         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3580         RSurf_DrawBatch();
3581 }
3582
3583 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3584 {
3585         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3586         R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3587         RSurf_DrawBatch();
3588 }
3589
3590 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3591 {
3592         int renders;
3593         int i;
3594         int stop;
3595         int newfirstvertex;
3596         int newlastvertex;
3597         int newnumtriangles;
3598         int *newe;
3599         const int *e;
3600         float *c;
3601         int maxtriangles = 1024;
3602         int newelements[1024*3];
3603         R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3604         for (renders = 0;renders < 4;renders++)
3605         {
3606                 stop = true;
3607                 newfirstvertex = 0;
3608                 newlastvertex = 0;
3609                 newnumtriangles = 0;
3610                 newe = newelements;
3611                 // due to low fillrate on the cards this vertex lighting path is
3612                 // designed for, we manually cull all triangles that do not
3613                 // contain a lit vertex
3614                 // this builds batches of triangles from multiple surfaces and
3615                 // renders them at once
3616                 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3617                 {
3618                         if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3619                         {
3620                                 if (newnumtriangles)
3621                                 {
3622                                         newfirstvertex = min(newfirstvertex, e[0]);
3623                                         newlastvertex  = max(newlastvertex, e[0]);
3624                                 }
3625                                 else
3626                                 {
3627                                         newfirstvertex = e[0];
3628                                         newlastvertex = e[0];
3629                                 }
3630                                 newfirstvertex = min(newfirstvertex, e[1]);
3631                                 newlastvertex  = max(newlastvertex, e[1]);
3632                                 newfirstvertex = min(newfirstvertex, e[2]);
3633                                 newlastvertex  = max(newlastvertex, e[2]);
3634                                 newe[0] = e[0];
3635                                 newe[1] = e[1];
3636                                 newe[2] = e[2];
3637                                 newnumtriangles++;
3638                                 newe += 3;
3639                                 if (newnumtriangles >= maxtriangles)
3640                                 {
3641                                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3642                                         newnumtriangles = 0;
3643                                         newe = newelements;
3644                                         stop = false;
3645                                 }
3646                         }
3647                 }
3648                 if (newnumtriangles >= 1)
3649                 {
3650                         R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3651                         stop = false;
3652                 }
3653                 // if we couldn't find any lit triangles, exit early
3654                 if (stop)
3655                         break;
3656                 // now reduce the intensity for the next overbright pass
3657                 // we have to clamp to 0 here incase the drivers have improper
3658                 // handling of negative colors
3659                 // (some old drivers even have improper handling of >1 color)
3660                 stop = true;
3661                 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3662                 {
3663                         if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3664                         {
3665                                 c[0] = max(0, c[0] - 1);
3666                                 c[1] = max(0, c[1] - 1);
3667                                 c[2] = max(0, c[2] - 1);
3668                                 stop = false;
3669                         }
3670                         else
3671                                 VectorClear(c);
3672                 }
3673                 // another check...
3674                 if (stop)
3675                         break;
3676         }
3677 }
3678
3679 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3680 {
3681         // OpenGL 1.1 path (anything)
3682         float ambientcolorbase[3], diffusecolorbase[3];
3683         float ambientcolorpants[3], diffusecolorpants[3];
3684         float ambientcolorshirt[3], diffusecolorshirt[3];
3685         const float *surfacecolor = rsurface.texture->dlightcolor;
3686         const float *surfacepants = rsurface.colormap_pantscolor;
3687         const float *surfaceshirt = rsurface.colormap_shirtcolor;
3688         rtexture_t *basetexture = rsurface.texture->basetexture;
3689         rtexture_t *pantstexture = rsurface.texture->pantstexture;
3690         rtexture_t *shirttexture = rsurface.texture->shirttexture;
3691         qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3692         qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3693         ambientscale *= 2 * r_refdef.view.colorscale;
3694         diffusescale *= 2 * r_refdef.view.colorscale;
3695         ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3696         diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3697         ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3698         diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3699         ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3700         diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3701         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3702         rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3703         R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3704         R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3705         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3706         R_Mesh_TexBind(0, basetexture);
3707         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3708         R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3709         switch(r_shadow_rendermode)
3710         {
3711         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3712                 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3713                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3714                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3715                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3716                 break;
3717         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3718                 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3719                 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3720                 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3721                 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3722                 // fall through
3723         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3724                 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3725                 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3726                 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3727                 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3728                 break;
3729         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3730                 break;
3731         default:
3732                 break;
3733         }
3734         //R_Mesh_TexBind(0, basetexture);
3735         R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3736         if (dopants)
3737         {
3738                 R_Mesh_TexBind(0, pantstexture);
3739                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3740         }
3741         if (doshirt)
3742         {
3743                 R_Mesh_TexBind(0, shirttexture);
3744                 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3745         }
3746 }
3747
3748 extern cvar_t gl_lightmaps;
3749 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3750 {
3751         float ambientscale, diffusescale, specularscale;
3752         qboolean negated;
3753         float lightcolor[3];
3754         VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3755         ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3756         diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3757         specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3758         if (!r_shadow_usenormalmap.integer)
3759         {
3760                 ambientscale += 1.0f * diffusescale;
3761                 diffusescale = 0;
3762                 specularscale = 0;
3763         }
3764         if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3765                 return;
3766         negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3767         if(negated)
3768         {
3769                 VectorNegate(lightcolor, lightcolor);
3770                 GL_BlendEquationSubtract(true);
3771         }
3772         RSurf_SetupDepthAndCulling();
3773         switch (r_shadow_rendermode)
3774         {
3775         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3776                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3777                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3778                 break;
3779         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3780                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3781                 break;
3782         case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3783         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3784         case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3785         case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3786                 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3787                 break;
3788         default:
3789                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3790                 break;
3791         }
3792         if(negated)
3793                 GL_BlendEquationSubtract(false);
3794 }
3795
3796 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)
3797 {
3798         matrix4x4_t tempmatrix = *matrix;
3799         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3800
3801         // if this light has been compiled before, free the associated data
3802         R_RTLight_Uncompile(rtlight);
3803
3804         // clear it completely to avoid any lingering data
3805         memset(rtlight, 0, sizeof(*rtlight));
3806
3807         // copy the properties
3808         rtlight->matrix_lighttoworld = tempmatrix;
3809         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3810         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3811         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3812         VectorCopy(color, rtlight->color);
3813         rtlight->cubemapname[0] = 0;
3814         if (cubemapname && cubemapname[0])
3815                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3816         rtlight->shadow = shadow;
3817         rtlight->corona = corona;
3818         rtlight->style = style;
3819         rtlight->isstatic = isstatic;
3820         rtlight->coronasizescale = coronasizescale;
3821         rtlight->ambientscale = ambientscale;
3822         rtlight->diffusescale = diffusescale;
3823         rtlight->specularscale = specularscale;
3824         rtlight->flags = flags;
3825
3826         // compute derived data
3827         //rtlight->cullradius = rtlight->radius;
3828         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3829         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3830         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3831         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3832         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3833         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3834         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3835 }
3836
3837 // compiles rtlight geometry
3838 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3839 void R_RTLight_Compile(rtlight_t *rtlight)
3840 {
3841         int i;
3842         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3843         int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3844         entity_render_t *ent = r_refdef.scene.worldentity;
3845         dp_model_t *model = r_refdef.scene.worldmodel;
3846         unsigned char *data;
3847         shadowmesh_t *mesh;
3848
3849         // compile the light
3850         rtlight->compiled = true;
3851         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3852         rtlight->static_numleafs = 0;
3853         rtlight->static_numleafpvsbytes = 0;
3854         rtlight->static_leaflist = NULL;
3855         rtlight->static_leafpvs = NULL;
3856         rtlight->static_numsurfaces = 0;
3857         rtlight->static_surfacelist = NULL;
3858         rtlight->static_shadowmap_receivers = 0x3F;
3859         rtlight->static_shadowmap_casters = 0x3F;
3860         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3861         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3862         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3863         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3864         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3865         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3866
3867         if (model && model->GetLightInfo)
3868         {
3869                 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3870                 r_shadow_compilingrtlight = rtlight;
3871                 R_FrameData_SetMark();
3872                 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);
3873                 R_FrameData_ReturnToMark();
3874                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3875                 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3876                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3877                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3878                 rtlight->static_numsurfaces = numsurfaces;
3879                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3880                 rtlight->static_numleafs = numleafs;
3881                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3882                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3883                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3884                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3885                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3886                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3887                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3888                 if (rtlight->static_numsurfaces)
3889                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3890                 if (rtlight->static_numleafs)
3891                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3892                 if (rtlight->static_numleafpvsbytes)
3893                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3894                 if (rtlight->static_numshadowtrispvsbytes)
3895                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3896                 if (rtlight->static_numlighttrispvsbytes)
3897                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3898                 R_FrameData_SetMark();
3899                 switch (rtlight->shadowmode)
3900                 {
3901                 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3902                         if (model->CompileShadowMap && rtlight->shadow)
3903                                 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3904                         break;
3905                 default:
3906                         if (model->CompileShadowVolume && rtlight->shadow)
3907                                 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3908                         break;
3909                 }
3910                 R_FrameData_ReturnToMark();
3911                 // now we're done compiling the rtlight
3912                 r_shadow_compilingrtlight = NULL;
3913         }
3914
3915
3916         // use smallest available cullradius - box radius or light radius
3917         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3918         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3919
3920         shadowzpasstris = 0;
3921         if (rtlight->static_meshchain_shadow_zpass)
3922                 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3923                         shadowzpasstris += mesh->numtriangles;
3924
3925         shadowzfailtris = 0;
3926         if (rtlight->static_meshchain_shadow_zfail)
3927                 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3928                         shadowzfailtris += mesh->numtriangles;
3929
3930         lighttris = 0;
3931         if (rtlight->static_numlighttrispvsbytes)
3932                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3933                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3934                                 lighttris++;
3935
3936         shadowtris = 0;
3937         if (rtlight->static_numshadowtrispvsbytes)
3938                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3939                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3940                                 shadowtris++;
3941
3942         if (developer_extra.integer)
3943                 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);
3944 }
3945
3946 void R_RTLight_Uncompile(rtlight_t *rtlight)
3947 {
3948         if (rtlight->compiled)
3949         {
3950                 if (rtlight->static_meshchain_shadow_zpass)
3951                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3952                 rtlight->static_meshchain_shadow_zpass = NULL;
3953                 if (rtlight->static_meshchain_shadow_zfail)
3954                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3955                 rtlight->static_meshchain_shadow_zfail = NULL;
3956                 if (rtlight->static_meshchain_shadow_shadowmap)
3957                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3958                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3959                 // these allocations are grouped
3960                 if (rtlight->static_surfacelist)
3961                         Mem_Free(rtlight->static_surfacelist);
3962                 rtlight->static_numleafs = 0;
3963                 rtlight->static_numleafpvsbytes = 0;
3964                 rtlight->static_leaflist = NULL;
3965                 rtlight->static_leafpvs = NULL;
3966                 rtlight->static_numsurfaces = 0;
3967                 rtlight->static_surfacelist = NULL;
3968                 rtlight->static_numshadowtrispvsbytes = 0;
3969                 rtlight->static_shadowtrispvs = NULL;
3970                 rtlight->static_numlighttrispvsbytes = 0;
3971                 rtlight->static_lighttrispvs = NULL;
3972                 rtlight->compiled = false;
3973         }
3974 }
3975
3976 void R_Shadow_UncompileWorldLights(void)
3977 {
3978         size_t lightindex;
3979         dlight_t *light;
3980         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3981         for (lightindex = 0;lightindex < range;lightindex++)
3982         {
3983                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3984                 if (!light)
3985                         continue;
3986                 R_RTLight_Uncompile(&light->rtlight);
3987         }
3988 }
3989
3990 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3991 {
3992         int i, j;
3993         mplane_t plane;
3994         // reset the count of frustum planes
3995         // see rtlight->cached_frustumplanes definition for how much this array
3996         // can hold
3997         rtlight->cached_numfrustumplanes = 0;
3998
3999         if (r_trippy.integer)
4000                 return;
4001
4002         // haven't implemented a culling path for ortho rendering
4003         if (!r_refdef.view.useperspective)
4004         {
4005                 // check if the light is on screen and copy the 4 planes if it is
4006                 for (i = 0;i < 4;i++)
4007                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4008                                 break;
4009                 if (i == 4)
4010                         for (i = 0;i < 4;i++)
4011                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4012                 return;
4013         }
4014
4015 #if 1
4016         // generate a deformed frustum that includes the light origin, this is
4017         // used to cull shadow casting surfaces that can not possibly cast a
4018         // shadow onto the visible light-receiving surfaces, which can be a
4019         // performance gain
4020         //
4021         // if the light origin is onscreen the result will be 4 planes exactly
4022         // if the light origin is offscreen on only one axis the result will
4023         // be exactly 5 planes (split-side case)
4024         // if the light origin is offscreen on two axes the result will be
4025         // exactly 4 planes (stretched corner case)
4026         for (i = 0;i < 4;i++)
4027         {
4028                 // quickly reject standard frustum planes that put the light
4029                 // origin outside the frustum
4030                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
4031                         continue;
4032                 // copy the plane
4033                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
4034         }
4035         // if all the standard frustum planes were accepted, the light is onscreen
4036         // otherwise we need to generate some more planes below...
4037         if (rtlight->cached_numfrustumplanes < 4)
4038         {
4039                 // at least one of the stock frustum planes failed, so we need to
4040                 // create one or two custom planes to enclose the light origin
4041                 for (i = 0;i < 4;i++)
4042                 {
4043                         // create a plane using the view origin and light origin, and a
4044                         // single point from the frustum corner set
4045                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
4046                         VectorNormalize(plane.normal);
4047                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
4048                         // see if this plane is backwards and flip it if so
4049                         for (j = 0;j < 4;j++)
4050                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4051                                         break;
4052                         if (j < 4)
4053                         {
4054                                 VectorNegate(plane.normal, plane.normal);
4055                                 plane.dist *= -1;
4056                                 // flipped plane, test again to see if it is now valid
4057                                 for (j = 0;j < 4;j++)
4058                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
4059                                                 break;
4060                                 // if the plane is still not valid, then it is dividing the
4061                                 // frustum and has to be rejected
4062                                 if (j < 4)
4063                                         continue;
4064                         }
4065                         // we have created a valid plane, compute extra info
4066                         PlaneClassify(&plane);
4067                         // copy the plane
4068                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4069 #if 1
4070                         // if we've found 5 frustum planes then we have constructed a
4071                         // proper split-side case and do not need to keep searching for
4072                         // planes to enclose the light origin
4073                         if (rtlight->cached_numfrustumplanes == 5)
4074                                 break;
4075 #endif
4076                 }
4077         }
4078 #endif
4079
4080 #if 0
4081         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
4082         {
4083                 plane = rtlight->cached_frustumplanes[i];
4084                 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));
4085         }
4086 #endif
4087
4088 #if 0
4089         // now add the light-space box planes if the light box is rotated, as any
4090         // caster outside the oriented light box is irrelevant (even if it passed
4091         // the worldspace light box, which is axial)
4092         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
4093         {
4094                 for (i = 0;i < 6;i++)
4095                 {
4096                         vec3_t v;
4097                         VectorClear(v);
4098                         v[i >> 1] = (i & 1) ? -1 : 1;
4099                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
4100                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
4101                         plane.dist = VectorNormalizeLength(plane.normal);
4102                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
4103                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4104                 }
4105         }
4106 #endif
4107
4108 #if 0
4109         // add the world-space reduced box planes
4110         for (i = 0;i < 6;i++)
4111         {
4112                 VectorClear(plane.normal);
4113                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
4114                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
4115                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
4116         }
4117 #endif
4118
4119 #if 0
4120         {
4121         int j, oldnum;
4122         vec3_t points[8];
4123         vec_t bestdist;
4124         // reduce all plane distances to tightly fit the rtlight cull box, which
4125         // is in worldspace
4126         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4127         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
4128         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4129         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
4130         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4131         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
4132         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4133         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
4134         oldnum = rtlight->cached_numfrustumplanes;
4135         rtlight->cached_numfrustumplanes = 0;
4136         for (j = 0;j < oldnum;j++)
4137         {
4138                 // find the nearest point on the box to this plane
4139                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
4140                 for (i = 1;i < 8;i++)
4141                 {
4142                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
4143                         if (bestdist > dist)
4144                                 bestdist = dist;
4145                 }
4146                 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);
4147                 // if the nearest point is near or behind the plane, we want this
4148                 // plane, otherwise the plane is useless as it won't cull anything
4149                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
4150                 {
4151                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
4152                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
4153                 }
4154         }
4155         }
4156 #endif
4157 }
4158
4159 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
4160 {
4161         shadowmesh_t *mesh;
4162
4163         RSurf_ActiveWorldEntity();
4164
4165         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4166         {
4167                 CHECKGLERROR
4168                 GL_CullFace(GL_NONE);
4169                 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
4170                 for (;mesh;mesh = mesh->next)
4171                 {
4172                         if (!mesh->sidetotals[r_shadow_shadowmapside])
4173                                 continue;
4174                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
4175                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4176                         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);
4177                 }
4178                 CHECKGLERROR
4179         }
4180         else if (r_refdef.scene.worldentity->model)
4181                 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);
4182
4183         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4184 }
4185
4186 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
4187 {
4188         qboolean zpass = false;
4189         shadowmesh_t *mesh;
4190         int t, tend;
4191         int surfacelistindex;
4192         msurface_t *surface;
4193
4194         // if triangle neighbors are disabled, shadowvolumes are disabled
4195         if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
4196                 return;
4197
4198         RSurf_ActiveWorldEntity();
4199
4200         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4201         {
4202                 CHECKGLERROR
4203                 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
4204                 {
4205                         zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
4206                         R_Shadow_RenderMode_StencilShadowVolumes(zpass);
4207                 }
4208                 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
4209                 for (;mesh;mesh = mesh->next)
4210                 {
4211                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
4212                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
4213                         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
4214                         {
4215                                 // increment stencil if frontface is infront of depthbuffer
4216                                 GL_CullFace(r_refdef.view.cullface_back);
4217                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
4218                                 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);
4219                                 // decrement stencil if backface is infront of depthbuffer
4220                                 GL_CullFace(r_refdef.view.cullface_front);
4221                                 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
4222                         }
4223                         else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
4224                         {
4225                                 // decrement stencil if backface is behind depthbuffer
4226                                 GL_CullFace(r_refdef.view.cullface_front);
4227                                 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
4228                                 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);
4229                                 // increment stencil if frontface is behind depthbuffer
4230                                 GL_CullFace(r_refdef.view.cullface_back);
4231                                 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
4232                         }
4233                         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);
4234                 }
4235                 CHECKGLERROR
4236         }
4237         else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
4238         {
4239                 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
4240                 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
4241                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
4242                 {
4243                         surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
4244                         for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
4245                                 if (CHECKPVSBIT(trispvs, t))
4246                                         shadowmarklist[numshadowmark++] = t;
4247                 }
4248                 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);
4249         }
4250         else if (numsurfaces)
4251         {
4252                 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);
4253         }
4254
4255         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4256 }
4257
4258 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
4259 {
4260         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
4261         vec_t relativeshadowradius;
4262         RSurf_ActiveModelEntity(ent, false, false, false);
4263         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
4264         // we need to re-init the shader for each entity because the matrix changed
4265         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
4266         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
4267         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
4268         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
4269         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
4270         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
4271         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
4272         switch (r_shadow_rendermode)
4273         {
4274         case R_SHADOW_RENDERMODE_SHADOWMAP2D:
4275                 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4276                 break;
4277         default:
4278                 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4279                 break;
4280         }
4281         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4282 }
4283
4284 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
4285 {
4286         // set up properties for rendering light onto this entity
4287         RSurf_ActiveModelEntity(ent, true, true, false);
4288         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
4289         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4290         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4291         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4292 }
4293
4294 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
4295 {
4296         if (!r_refdef.scene.worldmodel->DrawLight)
4297                 return;
4298
4299         // set up properties for rendering light onto this entity
4300         RSurf_ActiveWorldEntity();
4301         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
4302         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
4303         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
4304         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
4305
4306         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
4307
4308         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4309 }
4310
4311 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
4312 {
4313         dp_model_t *model = ent->model;
4314         if (!model->DrawLight)
4315                 return;
4316
4317         R_Shadow_SetupEntityLight(ent);
4318
4319         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
4320
4321         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4322 }
4323
4324 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
4325 {
4326         int i;
4327         float f;
4328         int numleafs, numsurfaces;
4329         int *leaflist, *surfacelist;
4330         unsigned char *leafpvs;
4331         unsigned char *shadowtrispvs;
4332         unsigned char *lighttrispvs;
4333         //unsigned char *surfacesides;
4334         int numlightentities;
4335         int numlightentities_noselfshadow;
4336         int numshadowentities;
4337         int numshadowentities_noselfshadow;
4338         static entity_render_t *lightentities[MAX_EDICTS];
4339         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
4340         static entity_render_t *shadowentities[MAX_EDICTS];
4341         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
4342         qboolean nolight;
4343         qboolean castshadows;
4344
4345         rtlight->draw = false;
4346         rtlight->cached_numlightentities               = 0;
4347         rtlight->cached_numlightentities_noselfshadow  = 0;
4348         rtlight->cached_numshadowentities              = 0;
4349         rtlight->cached_numshadowentities_noselfshadow = 0;
4350         rtlight->cached_numsurfaces                    = 0;
4351         rtlight->cached_lightentities                  = NULL;
4352         rtlight->cached_lightentities_noselfshadow     = NULL;
4353         rtlight->cached_shadowentities                 = NULL;
4354         rtlight->cached_shadowentities_noselfshadow    = NULL;
4355         rtlight->cached_shadowtrispvs                  = NULL;
4356         rtlight->cached_lighttrispvs                   = NULL;
4357         rtlight->cached_surfacelist                    = NULL;
4358
4359         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
4360         // skip lights that are basically invisible (color 0 0 0)
4361         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
4362
4363         // loading is done before visibility checks because loading should happen
4364         // all at once at the start of a level, not when it stalls gameplay.
4365         // (especially important to benchmarks)
4366         // compile light
4367         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
4368         {
4369                 if (rtlight->compiled)
4370                         R_RTLight_Uncompile(rtlight);
4371                 R_RTLight_Compile(rtlight);
4372         }
4373
4374         // load cubemap
4375         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
4376
4377         // look up the light style value at this time
4378         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4379         VectorScale(rtlight->color, f, rtlight->currentcolor);
4380         /*
4381         if (rtlight->selected)
4382         {
4383                 f = 2 + sin(realtime * M_PI * 4.0);
4384                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
4385         }
4386         */
4387
4388         // if lightstyle is currently off, don't draw the light
4389         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
4390                 return;
4391
4392         // skip processing on corona-only lights
4393         if (nolight)
4394                 return;
4395
4396         // if the light box is offscreen, skip it
4397         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4398                 return;
4399
4400         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4401         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4402
4403         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4404
4405         // 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
4406         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4407                 return;
4408
4409         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4410         {
4411                 // compiled light, world available and can receive realtime lighting
4412                 // retrieve leaf information
4413                 numleafs = rtlight->static_numleafs;
4414                 leaflist = rtlight->static_leaflist;
4415                 leafpvs = rtlight->static_leafpvs;
4416                 numsurfaces = rtlight->static_numsurfaces;
4417                 surfacelist = rtlight->static_surfacelist;
4418                 //surfacesides = NULL;
4419                 shadowtrispvs = rtlight->static_shadowtrispvs;
4420                 lighttrispvs = rtlight->static_lighttrispvs;
4421         }
4422         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4423         {
4424                 // dynamic light, world available and can receive realtime lighting
4425                 // calculate lit surfaces and leafs
4426                 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);
4427                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4428                 leaflist = r_shadow_buffer_leaflist;
4429                 leafpvs = r_shadow_buffer_leafpvs;
4430                 surfacelist = r_shadow_buffer_surfacelist;
4431                 //surfacesides = r_shadow_buffer_surfacesides;
4432                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4433                 lighttrispvs = r_shadow_buffer_lighttrispvs;
4434                 // if the reduced leaf bounds are offscreen, skip it
4435                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4436                         return;
4437         }
4438         else
4439         {
4440                 // no world
4441                 numleafs = 0;
4442                 leaflist = NULL;
4443                 leafpvs = NULL;
4444                 numsurfaces = 0;
4445                 surfacelist = NULL;
4446                 //surfacesides = NULL;
4447                 shadowtrispvs = NULL;
4448                 lighttrispvs = NULL;
4449         }
4450         // check if light is illuminating any visible leafs
4451         if (numleafs)
4452         {
4453                 for (i = 0;i < numleafs;i++)
4454                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4455                                 break;
4456                 if (i == numleafs)
4457                         return;
4458         }
4459
4460         // make a list of lit entities and shadow casting entities
4461         numlightentities = 0;
4462         numlightentities_noselfshadow = 0;
4463         numshadowentities = 0;
4464         numshadowentities_noselfshadow = 0;
4465
4466         // add dynamic entities that are lit by the light
4467         for (i = 0;i < r_refdef.scene.numentities;i++)
4468         {
4469                 dp_model_t *model;
4470                 entity_render_t *ent = r_refdef.scene.entities[i];
4471                 vec3_t org;
4472                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4473                         continue;
4474                 // skip the object entirely if it is not within the valid
4475                 // shadow-casting region (which includes the lit region)
4476                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4477                         continue;
4478                 if (!(model = ent->model))
4479                         continue;
4480                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4481                 {
4482                         // this entity wants to receive light, is visible, and is
4483                         // inside the light box
4484                         // TODO: check if the surfaces in the model can receive light
4485                         // so now check if it's in a leaf seen by the light
4486                         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))
4487                                 continue;
4488                         if (ent->flags & RENDER_NOSELFSHADOW)
4489                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4490                         else
4491                                 lightentities[numlightentities++] = ent;
4492                         // since it is lit, it probably also casts a shadow...
4493                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4494                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4495                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4496                         {
4497                                 // note: exterior models without the RENDER_NOSELFSHADOW
4498                                 // flag still create a RENDER_NOSELFSHADOW shadow but
4499                                 // are lit normally, this means that they are
4500                                 // self-shadowing but do not shadow other
4501                                 // RENDER_NOSELFSHADOW entities such as the gun
4502                                 // (very weird, but keeps the player shadow off the gun)
4503                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4504                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4505                                 else
4506                                         shadowentities[numshadowentities++] = ent;
4507                         }
4508                 }
4509                 else if (ent->flags & RENDER_SHADOW)
4510                 {
4511                         // this entity is not receiving light, but may still need to
4512                         // cast a shadow...
4513                         // TODO: check if the surfaces in the model can cast shadow
4514                         // now check if it is in a leaf seen by the light
4515                         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))
4516                                 continue;
4517                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
4518                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4519                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4520                         {
4521                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4522                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4523                                 else
4524                                         shadowentities[numshadowentities++] = ent;
4525                         }
4526                 }
4527         }
4528
4529         // return if there's nothing at all to light
4530         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4531                 return;
4532
4533         // count this light in the r_speeds
4534         r_refdef.stats[r_stat_lights]++;
4535
4536         // flag it as worth drawing later
4537         rtlight->draw = true;
4538
4539         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4540         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4541         if (!castshadows)
4542                 numshadowentities = numshadowentities_noselfshadow = 0;
4543
4544         // cache all the animated entities that cast a shadow but are not visible
4545         for (i = 0;i < numshadowentities;i++)
4546                 R_AnimCache_GetEntity(shadowentities[i], false, false);
4547         for (i = 0;i < numshadowentities_noselfshadow;i++)
4548                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4549
4550         // allocate some temporary memory for rendering this light later in the frame
4551         // reusable buffers need to be copied, static data can be used as-is
4552         rtlight->cached_numlightentities               = numlightentities;
4553         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
4554         rtlight->cached_numshadowentities              = numshadowentities;
4555         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4556         rtlight->cached_numsurfaces                    = numsurfaces;
4557         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4558         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4559         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4560         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4561         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4562         {
4563                 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4564                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4565                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4566                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4567                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4568         }
4569         else
4570         {
4571                 // compiled light data
4572                 rtlight->cached_shadowtrispvs = shadowtrispvs;
4573                 rtlight->cached_lighttrispvs = lighttrispvs;
4574                 rtlight->cached_surfacelist = surfacelist;
4575         }
4576 }
4577
4578 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4579 {
4580         int i;
4581         int numsurfaces;
4582         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4583         int numlightentities;
4584         int numlightentities_noselfshadow;
4585         int numshadowentities;
4586         int numshadowentities_noselfshadow;
4587         entity_render_t **lightentities;
4588         entity_render_t **lightentities_noselfshadow;
4589         entity_render_t **shadowentities;
4590         entity_render_t **shadowentities_noselfshadow;
4591         int *surfacelist;
4592         static unsigned char entitysides[MAX_EDICTS];
4593         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4594         vec3_t nearestpoint;
4595         vec_t distance;
4596         qboolean castshadows;
4597         int lodlinear;
4598
4599         // check if we cached this light this frame (meaning it is worth drawing)
4600         if (!rtlight->draw)
4601                 return;
4602
4603         numlightentities = rtlight->cached_numlightentities;
4604         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4605         numshadowentities = rtlight->cached_numshadowentities;
4606         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4607         numsurfaces = rtlight->cached_numsurfaces;
4608         lightentities = rtlight->cached_lightentities;
4609         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4610         shadowentities = rtlight->cached_shadowentities;
4611         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4612         shadowtrispvs = rtlight->cached_shadowtrispvs;
4613         lighttrispvs = rtlight->cached_lighttrispvs;
4614         surfacelist = rtlight->cached_surfacelist;
4615
4616         // set up a scissor rectangle for this light
4617         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4618                 return;
4619
4620         // don't let sound skip if going slow
4621         if (r_refdef.scene.extraupdate)
4622                 S_ExtraUpdate ();
4623
4624         // make this the active rtlight for rendering purposes
4625         R_Shadow_RenderMode_ActiveLight(rtlight);
4626
4627         if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4628         {
4629                 // optionally draw visible shape of the shadow volumes
4630                 // for performance analysis by level designers
4631                 R_Shadow_RenderMode_VisibleShadowVolumes();
4632                 if (numsurfaces)
4633                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4634                 for (i = 0;i < numshadowentities;i++)
4635                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4636                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4637                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4638                 R_Shadow_RenderMode_VisibleLighting(false, false);
4639         }
4640
4641         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4642         {
4643                 // optionally draw the illuminated areas
4644                 // for performance analysis by level designers
4645                 R_Shadow_RenderMode_VisibleLighting(false, false);
4646                 if (numsurfaces)
4647                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4648                 for (i = 0;i < numlightentities;i++)
4649                         R_Shadow_DrawEntityLight(lightentities[i]);
4650                 for (i = 0;i < numlightentities_noselfshadow;i++)
4651                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4652         }
4653
4654         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4655
4656         nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4657         nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4658         nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4659         distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4660
4661         lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4662         //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4663         lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4664
4665         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4666         {
4667                 float borderbias;
4668                 int side;
4669                 int size;
4670                 int castermask = 0;
4671                 int receivermask = 0;
4672                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4673                 Matrix4x4_Abs(&radiustolight);
4674
4675                 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4676                         
4677                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4678
4679                 surfacesides = NULL;
4680                 if (numsurfaces)
4681                 {
4682                         if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4683                         {
4684                                 castermask = rtlight->static_shadowmap_casters;
4685                                 receivermask = rtlight->static_shadowmap_receivers;
4686                         }
4687                         else
4688                         {
4689                                 surfacesides = r_shadow_buffer_surfacesides;
4690                                 for(i = 0;i < numsurfaces;i++)
4691                                 {
4692                                         msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4693                                         surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);           
4694                                         castermask |= surfacesides[i];
4695                                         receivermask |= surfacesides[i];
4696                                 }
4697                         }
4698                 }
4699                 if (receivermask < 0x3F) 
4700                 {
4701                         for (i = 0;i < numlightentities;i++)
4702                                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4703                         if (receivermask < 0x3F)
4704                                 for(i = 0; i < numlightentities_noselfshadow;i++)
4705                                         receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4706                 }
4707
4708                 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4709
4710                 if (receivermask)
4711                 {
4712                         for (i = 0;i < numshadowentities;i++)
4713                                 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4714                         for (i = 0;i < numshadowentities_noselfshadow;i++)
4715                                 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias)); 
4716                 }
4717
4718                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
4719
4720                 // render shadow casters into 6 sided depth texture
4721                 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4722                 {
4723                         R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4724                         if (! (castermask & (1 << side))) continue;
4725                         if (numsurfaces)
4726                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4727                         for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4728                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
4729                 }
4730
4731                 if (numlightentities_noselfshadow)
4732                 {
4733                         // render lighting using the depth texture as shadowmap
4734                         // draw lighting in the unmasked areas
4735                         R_Shadow_RenderMode_Lighting(false, false, true);
4736                         for (i = 0;i < numlightentities_noselfshadow;i++)
4737                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4738                 }
4739
4740                 // render shadow casters into 6 sided depth texture
4741                 if (numshadowentities_noselfshadow)
4742                 {
4743                         for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4744                         {
4745                                 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4746                                 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4747                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4748                         }
4749                 }
4750
4751                 // render lighting using the depth texture as shadowmap
4752                 // draw lighting in the unmasked areas
4753                 R_Shadow_RenderMode_Lighting(false, false, true);
4754                 // draw lighting in the unmasked areas
4755                 if (numsurfaces)
4756                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4757                 for (i = 0;i < numlightentities;i++)
4758                         R_Shadow_DrawEntityLight(lightentities[i]);
4759         }
4760         else if (castshadows && vid.stencil)
4761         {
4762                 // draw stencil shadow volumes to mask off pixels that are in shadow
4763                 // so that they won't receive lighting
4764                 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4765                 R_Shadow_ClearStencil();
4766
4767                 if (numsurfaces)
4768                         R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4769                 for (i = 0;i < numshadowentities;i++)
4770                         R_Shadow_DrawEntityShadow(shadowentities[i]);
4771
4772                 // draw lighting in the unmasked areas
4773                 R_Shadow_RenderMode_Lighting(true, false, false);
4774                 for (i = 0;i < numlightentities_noselfshadow;i++)
4775                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4776
4777                 for (i = 0;i < numshadowentities_noselfshadow;i++)
4778                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4779
4780                 // draw lighting in the unmasked areas
4781                 R_Shadow_RenderMode_Lighting(true, false, false);
4782                 if (numsurfaces)
4783                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4784                 for (i = 0;i < numlightentities;i++)
4785                         R_Shadow_DrawEntityLight(lightentities[i]);
4786         }
4787         else
4788         {
4789                 // draw lighting in the unmasked areas
4790                 R_Shadow_RenderMode_Lighting(false, false, false);
4791                 if (numsurfaces)
4792                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4793                 for (i = 0;i < numlightentities;i++)
4794                         R_Shadow_DrawEntityLight(lightentities[i]);
4795                 for (i = 0;i < numlightentities_noselfshadow;i++)
4796                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4797         }
4798
4799         if (r_shadow_usingdeferredprepass)
4800         {
4801                 // when rendering deferred lighting, we simply rasterize the box
4802                 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4803                         R_Shadow_RenderMode_DrawDeferredLight(false, true);
4804                 else if (castshadows && vid.stencil)
4805                         R_Shadow_RenderMode_DrawDeferredLight(true, false);
4806                 else
4807                         R_Shadow_RenderMode_DrawDeferredLight(false, false);
4808         }
4809 }
4810
4811 static void R_Shadow_FreeDeferred(void)
4812 {
4813         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4814         r_shadow_prepassgeometryfbo = 0;
4815
4816         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4817         r_shadow_prepasslightingdiffusespecularfbo = 0;
4818
4819         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4820         r_shadow_prepasslightingdiffusefbo = 0;
4821
4822         if (r_shadow_prepassgeometrydepthbuffer)
4823                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4824         r_shadow_prepassgeometrydepthbuffer = NULL;
4825
4826         if (r_shadow_prepassgeometrynormalmaptexture)
4827                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4828         r_shadow_prepassgeometrynormalmaptexture = NULL;
4829
4830         if (r_shadow_prepasslightingdiffusetexture)
4831                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4832         r_shadow_prepasslightingdiffusetexture = NULL;
4833
4834         if (r_shadow_prepasslightingspeculartexture)
4835                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4836         r_shadow_prepasslightingspeculartexture = NULL;
4837 }
4838
4839 void R_Shadow_DrawPrepass(void)
4840 {
4841         int i;
4842         int flag;
4843         int lnum;
4844         size_t lightindex;
4845         dlight_t *light;
4846         size_t range;
4847         entity_render_t *ent;
4848         float clearcolor[4];
4849
4850         R_Mesh_ResetTextureState();
4851         GL_DepthMask(true);
4852         GL_ColorMask(1,1,1,1);
4853         GL_BlendFunc(GL_ONE, GL_ZERO);
4854         GL_Color(1,1,1,1);
4855         GL_DepthTest(true);
4856         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4857         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4858         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4859         if (r_timereport_active)
4860                 R_TimeReport("prepasscleargeom");
4861
4862         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4863                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4864         if (r_timereport_active)
4865                 R_TimeReport("prepassworld");
4866
4867         for (i = 0;i < r_refdef.scene.numentities;i++)
4868         {
4869                 if (!r_refdef.viewcache.entityvisible[i])
4870                         continue;
4871                 ent = r_refdef.scene.entities[i];
4872                 if (ent->model && ent->model->DrawPrepass != NULL)
4873                         ent->model->DrawPrepass(ent);
4874         }
4875
4876         if (r_timereport_active)
4877                 R_TimeReport("prepassmodels");
4878
4879         GL_DepthMask(false);
4880         GL_ColorMask(1,1,1,1);
4881         GL_Color(1,1,1,1);
4882         GL_DepthTest(true);
4883         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4884         Vector4Set(clearcolor, 0, 0, 0, 0);
4885         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4886         if (r_timereport_active)
4887                 R_TimeReport("prepassclearlit");
4888
4889         R_Shadow_RenderMode_Begin();
4890
4891         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4892         if (r_shadow_debuglight.integer >= 0)
4893         {
4894                 lightindex = r_shadow_debuglight.integer;
4895                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4896                 if (light && (light->flags & flag) && light->rtlight.draw)
4897                         R_Shadow_DrawLight(&light->rtlight);
4898         }
4899         else
4900         {
4901                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4902                 for (lightindex = 0;lightindex < range;lightindex++)
4903                 {
4904                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4905                         if (light && (light->flags & flag) && light->rtlight.draw)
4906                                 R_Shadow_DrawLight(&light->rtlight);
4907                 }
4908         }
4909         if (r_refdef.scene.rtdlight)
4910                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4911                         if (r_refdef.scene.lights[lnum]->draw)
4912                                 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4913
4914         R_Shadow_RenderMode_End();
4915
4916         if (r_timereport_active)
4917                 R_TimeReport("prepasslights");
4918 }
4919
4920 void R_Shadow_DrawLightSprites(void);
4921 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4922 {
4923         int flag;
4924         int lnum;
4925         size_t lightindex;
4926         dlight_t *light;
4927         size_t range;
4928         float f;
4929
4930         if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4931                 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4932                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) || 
4933                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer || 
4934                 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) || 
4935                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer || 
4936                 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
4937                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4938                 R_Shadow_FreeShadowMaps();
4939
4940         r_shadow_fb_fbo = fbo;
4941         r_shadow_fb_depthtexture = depthtexture;
4942         r_shadow_fb_colortexture = colortexture;
4943
4944         r_shadow_usingshadowmaportho = false;
4945
4946         switch (vid.renderpath)
4947         {
4948         case RENDERPATH_GL20:
4949         case RENDERPATH_D3D9:
4950         case RENDERPATH_D3D10:
4951         case RENDERPATH_D3D11:
4952         case RENDERPATH_SOFT:
4953 #ifndef USE_GLES2
4954                 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4955                 {
4956                         r_shadow_usingdeferredprepass = false;
4957                         if (r_shadow_prepass_width)
4958                                 R_Shadow_FreeDeferred();
4959                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4960                         break;
4961                 }
4962
4963                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4964                 {
4965                         R_Shadow_FreeDeferred();
4966
4967                         r_shadow_usingdeferredprepass = true;
4968                         r_shadow_prepass_width = vid.width;
4969                         r_shadow_prepass_height = vid.height;
4970                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4971                         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);
4972                         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);
4973                         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);
4974
4975                         // set up the geometry pass fbo (depth + normalmap)
4976                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4977                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4978                         // render depth into a renderbuffer and other important properties into the normalmap texture
4979
4980                         // set up the lighting pass fbo (diffuse + specular)
4981                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4982                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4983                         // render diffuse into one texture and specular into another,
4984                         // with depth and normalmap bound as textures,
4985                         // with depth bound as attachment as well
4986
4987                         // set up the lighting pass fbo (diffuse)
4988                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4989                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4990                         // render diffuse into one texture,
4991                         // with depth and normalmap bound as textures,
4992                         // with depth bound as attachment as well
4993                 }
4994 #endif
4995                 break;
4996         case RENDERPATH_GL11:
4997         case RENDERPATH_GL13:
4998         case RENDERPATH_GLES1:
4999         case RENDERPATH_GLES2:
5000                 r_shadow_usingdeferredprepass = false;
5001                 break;
5002         }
5003
5004         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);
5005
5006         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5007         if (r_shadow_debuglight.integer >= 0)
5008         {
5009                 lightindex = r_shadow_debuglight.integer;
5010                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5011                 if (light)
5012                         R_Shadow_PrepareLight(&light->rtlight);
5013         }
5014         else
5015         {
5016                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5017                 for (lightindex = 0;lightindex < range;lightindex++)
5018                 {
5019                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5020                         if (light && (light->flags & flag))
5021                                 R_Shadow_PrepareLight(&light->rtlight);
5022                 }
5023         }
5024         if (r_refdef.scene.rtdlight)
5025         {
5026                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
5027                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
5028         }
5029         else if(gl_flashblend.integer)
5030         {
5031                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
5032                 {
5033                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
5034                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
5035                         VectorScale(rtlight->color, f, rtlight->currentcolor);
5036                 }
5037         }
5038
5039         if (r_editlights.integer)
5040                 R_Shadow_DrawLightSprites();
5041 }
5042
5043 void R_Shadow_DrawLights(void)
5044 {
5045         int flag;
5046         int lnum;
5047         size_t lightindex;
5048         dlight_t *light;
5049         size_t range;
5050
5051         R_Shadow_RenderMode_Begin();
5052
5053         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5054         if (r_shadow_debuglight.integer >= 0)
5055         {
5056                 lightindex = r_shadow_debuglight.integer;
5057                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5058                 if (light)
5059                         R_Shadow_DrawLight(&light->rtlight);
5060         }
5061         else
5062         {
5063                 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5064                 for (lightindex = 0;lightindex < range;lightindex++)
5065                 {
5066                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5067                         if (light && (light->flags & flag))
5068                                 R_Shadow_DrawLight(&light->rtlight);
5069                 }
5070         }
5071         if (r_refdef.scene.rtdlight)
5072                 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
5073                         R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
5074
5075         R_Shadow_RenderMode_End();
5076 }
5077
5078 #define MAX_MODELSHADOWS 1024
5079 static int r_shadow_nummodelshadows;
5080 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
5081
5082 void R_Shadow_PrepareModelShadows(void)
5083 {
5084         int i;
5085         float scale, size, radius, dot1, dot2;
5086         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5087         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
5088         entity_render_t *ent;
5089
5090         r_shadow_nummodelshadows = 0;
5091         if (!r_refdef.scene.numentities)
5092                 return;
5093
5094         switch (r_shadow_shadowmode)
5095         {
5096         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5097                 if (r_shadows.integer >= 2) 
5098                         break;
5099                 // fall through
5100         case R_SHADOW_SHADOWMODE_STENCIL:
5101                 if (!vid.stencil)
5102                         return;
5103                 for (i = 0;i < r_refdef.scene.numentities;i++)
5104                 {
5105                         ent = r_refdef.scene.entities[i];
5106                         if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5107                         {
5108                                 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5109                                         break;
5110                                 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5111                                 R_AnimCache_GetEntity(ent, false, false);
5112                         }
5113                 }
5114                 return;
5115         default:
5116                 return;
5117         }
5118
5119         size = 2*r_shadow_shadowmapmaxsize;
5120         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
5121         radius = 0.5f * size / scale;
5122
5123         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5124         VectorCopy(prvmshadowdir, shadowdir);
5125         VectorNormalize(shadowdir);
5126         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5127         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5128         if (fabs(dot1) <= fabs(dot2))
5129                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5130         else
5131                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5132         VectorNormalize(shadowforward);
5133         CrossProduct(shadowdir, shadowforward, shadowright);
5134         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5135         VectorCopy(prvmshadowfocus, shadowfocus);
5136         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5137         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5138         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5139         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5140         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5141                 dot1 = 1;
5142         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5143
5144         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5145         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5146         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5147         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
5148         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
5149         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
5150
5151         for (i = 0;i < r_refdef.scene.numentities;i++)
5152         {
5153                 ent = r_refdef.scene.entities[i];
5154                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
5155                         continue;
5156                 // cast shadows from anything of the map (submodels are optional)
5157                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
5158                 {
5159                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
5160                                 break;
5161                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
5162                         R_AnimCache_GetEntity(ent, false, false);
5163                 }
5164         }
5165 }
5166
5167 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5168 {
5169         int i;
5170         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
5171         entity_render_t *ent;
5172         vec3_t relativelightorigin;
5173         vec3_t relativelightdirection, relativeforward, relativeright;
5174         vec3_t relativeshadowmins, relativeshadowmaxs;
5175         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
5176         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
5177         float m[12];
5178         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
5179         r_viewport_t viewport;
5180         GLuint shadowfbo = 0;
5181         float clearcolor[4];
5182
5183         if (!r_shadow_nummodelshadows)
5184                 return;
5185
5186         switch (r_shadow_shadowmode)
5187         {
5188         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5189                 break;
5190         default:
5191                 return;
5192         }
5193
5194         r_shadow_fb_fbo = fbo;
5195         r_shadow_fb_depthtexture = depthtexture;
5196         r_shadow_fb_colortexture = colortexture;
5197
5198         R_ResetViewRendering3D(fbo, depthtexture, colortexture);
5199         R_Shadow_RenderMode_Begin();
5200         R_Shadow_RenderMode_ActiveLight(NULL);
5201
5202         switch (r_shadow_shadowmode)
5203         {
5204         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5205                 if (!r_shadow_shadowmap2ddepthtexture)
5206                         R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
5207                 shadowfbo = r_shadow_fbo2d;
5208                 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
5209                 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
5210                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
5211                 break;
5212         default:
5213                 break;
5214         }
5215
5216         size = 2*r_shadow_shadowmapmaxsize;
5217         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
5218         radius = 0.5f / scale;
5219         nearclip = -r_shadows_throwdistance.value;
5220         farclip = r_shadows_throwdistance.value;
5221         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);
5222
5223         r_shadow_shadowmap_parameters[0] = size;
5224         r_shadow_shadowmap_parameters[1] = size;
5225         r_shadow_shadowmap_parameters[2] = 1.0;
5226         r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
5227
5228         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5229         VectorCopy(prvmshadowdir, shadowdir);
5230         VectorNormalize(shadowdir);
5231         Math_atov(r_shadows_focus.string, prvmshadowfocus);
5232         VectorCopy(prvmshadowfocus, shadowfocus);
5233         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
5234         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
5235         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
5236         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
5237         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
5238         dot2 = DotProduct(r_refdef.view.up, shadowdir);
5239         if (fabs(dot1) <= fabs(dot2)) 
5240                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
5241         else
5242                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
5243         VectorNormalize(shadowforward);
5244         VectorM(scale, shadowforward, &m[0]);
5245         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
5246                 dot1 = 1;
5247         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
5248         CrossProduct(shadowdir, shadowforward, shadowright);
5249         VectorM(scale, shadowright, &m[4]);
5250         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
5251         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
5252         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
5253         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
5254         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
5255         R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL); 
5256
5257         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
5258
5259         if (r_shadow_shadowmap2ddepthbuffer)
5260                 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
5261         else
5262                 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
5263         R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
5264         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
5265         GL_DepthMask(true);
5266         GL_DepthTest(true);
5267         R_SetViewport(&viewport);
5268         GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
5269         Vector4Set(clearcolor, 1,1,1,1);
5270         // in D3D9 we have to render to a color texture shadowmap
5271         // in GL we render directly to a depth texture only
5272         if (r_shadow_shadowmap2ddepthbuffer)
5273                 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5274         else
5275                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
5276         // render into a slightly restricted region so that the borders of the
5277         // shadowmap area fade away, rather than streaking across everything
5278         // outside the usable area
5279         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
5280
5281         for (i = 0;i < r_shadow_nummodelshadows;i++)
5282         {
5283                 ent = r_shadow_modelshadows[i];
5284                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5285                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
5286                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5287                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
5288                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
5289                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5290                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5291                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5292                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
5293                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
5294                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
5295                 RSurf_ActiveModelEntity(ent, false, false, false);
5296                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
5297                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5298         }
5299
5300 #if 0
5301         if (r_test.integer)
5302         {
5303                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
5304                 CHECKGLERROR
5305                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
5306                 CHECKGLERROR
5307                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
5308                 Cvar_SetValueQuick(&r_test, 0);
5309                 Z_Free(rawpixels);
5310         }
5311 #endif
5312
5313         R_Shadow_RenderMode_End();
5314
5315         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
5316         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
5317         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1); 
5318         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
5319         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
5320         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
5321
5322         switch (vid.renderpath)
5323         {
5324         case RENDERPATH_GL11:
5325         case RENDERPATH_GL13:
5326         case RENDERPATH_GL20:
5327         case RENDERPATH_SOFT:
5328         case RENDERPATH_GLES1:
5329         case RENDERPATH_GLES2:
5330                 break;
5331         case RENDERPATH_D3D9:
5332         case RENDERPATH_D3D10:
5333         case RENDERPATH_D3D11:
5334 #ifdef MATRIX4x4_OPENGLORIENTATION
5335                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5336                 r_shadow_shadowmapmatrix.m[0][1]        *= -1.0f;
5337                 r_shadow_shadowmapmatrix.m[0][2]        *= -1.0f;
5338                 r_shadow_shadowmapmatrix.m[0][3]        *= -1.0f;
5339 #else
5340                 r_shadow_shadowmapmatrix.m[0][0]        *= -1.0f;
5341                 r_shadow_shadowmapmatrix.m[1][0]        *= -1.0f;
5342                 r_shadow_shadowmapmatrix.m[2][0]        *= -1.0f;
5343                 r_shadow_shadowmapmatrix.m[3][0]        *= -1.0f;
5344 #endif
5345                 break;
5346         }
5347
5348         r_shadow_usingshadowmaportho = true;
5349         switch (r_shadow_shadowmode)
5350         {
5351         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
5352                 r_shadow_usingshadowmap2d = true;
5353                 break;
5354         default:
5355                 break;
5356         }
5357 }
5358
5359 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
5360 {
5361         int i;
5362         float relativethrowdistance;
5363         entity_render_t *ent;
5364         vec3_t relativelightorigin;
5365         vec3_t relativelightdirection;
5366         vec3_t relativeshadowmins, relativeshadowmaxs;
5367         vec3_t tmp, shadowdir;
5368         prvm_vec3_t prvmshadowdir;
5369
5370         if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
5371                 return;
5372
5373         r_shadow_fb_fbo = fbo;
5374         r_shadow_fb_depthtexture = depthtexture;
5375         r_shadow_fb_colortexture = colortexture;
5376
5377         R_ResetViewRendering3D(fbo, depthtexture, colortexture);
5378         //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5379         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5380         R_Shadow_RenderMode_Begin();
5381         R_Shadow_RenderMode_ActiveLight(NULL);
5382         r_shadow_lightscissor[0] = r_refdef.view.x;
5383         r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
5384         r_shadow_lightscissor[2] = r_refdef.view.width;
5385         r_shadow_lightscissor[3] = r_refdef.view.height;
5386         R_Shadow_RenderMode_StencilShadowVolumes(false);
5387
5388         // get shadow dir
5389         if (r_shadows.integer == 2)
5390         {
5391                 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5392                 VectorCopy(prvmshadowdir, shadowdir);
5393                 VectorNormalize(shadowdir);
5394         }
5395
5396         R_Shadow_ClearStencil();
5397
5398         for (i = 0;i < r_shadow_nummodelshadows;i++)
5399         {
5400                 ent = r_shadow_modelshadows[i];
5401
5402                 // cast shadows from anything of the map (submodels are optional)
5403                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5404                 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5405                 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5406                 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5407                         Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5408                 else
5409                 {
5410                         if(ent->entitynumber != 0)
5411                         {
5412                                 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5413                                 {
5414                                         // FIXME handle this
5415                                         VectorNegate(ent->modellight_lightdir, relativelightdirection);
5416                                 }
5417                                 else
5418                                 {
5419                                         // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5420                                         int entnum, entnum2, recursion;
5421                                         entnum = entnum2 = ent->entitynumber;
5422                                         for(recursion = 32; recursion > 0; --recursion)
5423                                         {
5424                                                 entnum2 = cl.entities[entnum].state_current.tagentity;
5425                                                 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5426                                                         entnum = entnum2;
5427                                                 else
5428                                                         break;
5429                                         }
5430                                         if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5431                                         {
5432                                                 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5433                                                 // transform into modelspace of OUR entity
5434                                                 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5435                                                 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5436                                         }
5437                                         else
5438                                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5439                                 }
5440                         }
5441                         else
5442                                 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5443                 }
5444
5445                 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5446                 RSurf_ActiveModelEntity(ent, false, false, false);
5447                 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5448                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5449         }
5450
5451         // not really the right mode, but this will disable any silly stencil features
5452         R_Shadow_RenderMode_End();
5453
5454         // set up ortho view for rendering this pass
5455         //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5456         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5457         //GL_ScissorTest(true);
5458         //R_EntityMatrix(&identitymatrix);
5459         //R_Mesh_ResetTextureState();
5460         R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5461
5462         // set up a darkening blend on shadowed areas
5463         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5464         //GL_DepthRange(0, 1);
5465         //GL_DepthTest(false);
5466         //GL_DepthMask(false);
5467         //GL_PolygonOffset(0, 0);CHECKGLERROR
5468         GL_Color(0, 0, 0, r_shadows_darken.value);
5469         //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5470         //GL_DepthFunc(GL_ALWAYS);
5471         R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5472
5473         // apply the blend to the shadowed areas
5474         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5475         R_SetupShader_Generic_NoTexture(false, true);
5476         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5477
5478         // restore the viewport
5479         R_SetViewport(&r_refdef.view.viewport);
5480
5481         // restore other state to normal
5482         //R_Shadow_RenderMode_End();
5483 }
5484
5485 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5486 {
5487         float zdist;
5488         vec3_t centerorigin;
5489 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5490         float vertex3f[12];
5491 #endif
5492         // if it's too close, skip it
5493         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5494                 return;
5495         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5496         if (zdist < 32)
5497                 return;
5498         if (usequery && r_numqueries + 2 <= r_maxqueries)
5499         {
5500                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5501                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5502                 // 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
5503                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5504
5505                 switch(vid.renderpath)
5506                 {
5507                 case RENDERPATH_GL11:
5508                 case RENDERPATH_GL13:
5509                 case RENDERPATH_GL20:
5510                 case RENDERPATH_GLES1:
5511                 case RENDERPATH_GLES2:
5512 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5513                         CHECKGLERROR
5514                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5515                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5516                         GL_DepthFunc(GL_ALWAYS);
5517                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5518                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5519                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5520                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5521                         GL_DepthFunc(GL_LEQUAL);
5522                         qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5523                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5524                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5525                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5526                         qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5527                         CHECKGLERROR
5528 #endif
5529                         break;
5530                 case RENDERPATH_D3D9:
5531                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5532                         break;
5533                 case RENDERPATH_D3D10:
5534                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5535                         break;
5536                 case RENDERPATH_D3D11:
5537                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5538                         break;
5539                 case RENDERPATH_SOFT:
5540                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5541                         break;
5542                 }
5543         }
5544         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5545 }
5546
5547 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5548
5549 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5550 {
5551         vec3_t color;
5552         unsigned int occlude = 0;
5553         GLint allpixels = 0, visiblepixels = 0;
5554
5555         // now we have to check the query result
5556         if (rtlight->corona_queryindex_visiblepixels)
5557         {
5558                 switch(vid.renderpath)
5559                 {
5560                 case RENDERPATH_GL11:
5561                 case RENDERPATH_GL13:
5562                 case RENDERPATH_GL20:
5563                 case RENDERPATH_GLES1:
5564                 case RENDERPATH_GLES2:
5565 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5566                         CHECKGLERROR
5567                         // See if we can use the GPU-side method to prevent implicit sync
5568                         if (vid.support.arb_query_buffer_object) {
5569 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
5570                                 if (!r_shadow_occlusion_buf) {
5571                                         qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5572                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5573                                         qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5574                                 } else {
5575                                         qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5576                                 }
5577                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5578                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5579                                 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5580                                 occlude = MATERIALFLAG_OCCLUDE;
5581                         } else {
5582                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5583                                 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels); 
5584                                 if (visiblepixels < 1 || allpixels < 1)
5585                                         return;
5586                                 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5587                         }
5588                         cscale *= rtlight->corona_visibility;
5589                         CHECKGLERROR
5590                         break;
5591 #else
5592                         return;
5593 #endif
5594                 case RENDERPATH_D3D9:
5595                         Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5596                         return;
5597                 case RENDERPATH_D3D10:
5598                         Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5599                         return;
5600                 case RENDERPATH_D3D11:
5601                         Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5602                         return;
5603                 case RENDERPATH_SOFT:
5604                         //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5605                         return;
5606                 default:
5607                         return;
5608                 }
5609         }
5610         else
5611         {
5612                 // FIXME: these traces should scan all render entities instead of cl.world
5613                 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5614                         return;
5615         }
5616         VectorScale(rtlight->currentcolor, cscale, color);
5617         if (VectorLength(color) > (1.0f / 256.0f))
5618         {
5619                 float vertex3f[12];
5620                 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5621                 if(negated)
5622                 {
5623                         VectorNegate(color, color);
5624                         GL_BlendEquationSubtract(true);
5625                 }
5626                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5627                 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);
5628                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5629                 if(negated)
5630                         GL_BlendEquationSubtract(false);
5631         }
5632 }
5633
5634 void R_Shadow_DrawCoronas(void)
5635 {
5636         int i, flag;
5637         qboolean usequery = false;
5638         size_t lightindex;
5639         dlight_t *light;
5640         rtlight_t *rtlight;
5641         size_t range;
5642         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5643                 return;
5644         if (r_fb.water.renderingscene)
5645                 return;
5646         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5647         R_EntityMatrix(&identitymatrix);
5648
5649         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5650
5651         // check occlusion of coronas
5652         // use GL_ARB_occlusion_query if available
5653         // otherwise use raytraces
5654         r_numqueries = 0;
5655         switch (vid.renderpath)
5656         {
5657         case RENDERPATH_GL11:
5658         case RENDERPATH_GL13:
5659         case RENDERPATH_GL20:
5660         case RENDERPATH_GLES1:
5661         case RENDERPATH_GLES2:
5662                 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5663 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5664                 if (usequery)
5665                 {
5666                         GL_ColorMask(0,0,0,0);
5667                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5668                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5669                         {
5670                                 i = r_maxqueries;
5671                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5672                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5673                                 CHECKGLERROR
5674                                 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5675                                 CHECKGLERROR
5676                         }
5677                         RSurf_ActiveWorldEntity();
5678                         GL_BlendFunc(GL_ONE, GL_ZERO);
5679                         GL_CullFace(GL_NONE);
5680                         GL_DepthMask(false);
5681                         GL_DepthRange(0, 1);
5682                         GL_PolygonOffset(0, 0);
5683                         GL_DepthTest(true);
5684                         R_Mesh_ResetTextureState();
5685                         R_SetupShader_Generic_NoTexture(false, false);
5686                 }
5687 #endif
5688                 break;
5689         case RENDERPATH_D3D9:
5690                 usequery = false;
5691                 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5692                 break;
5693         case RENDERPATH_D3D10:
5694                 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5695                 break;
5696         case RENDERPATH_D3D11:
5697                 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5698                 break;
5699         case RENDERPATH_SOFT:
5700                 usequery = false;
5701                 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5702                 break;
5703         }
5704         for (lightindex = 0;lightindex < range;lightindex++)
5705         {
5706                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5707                 if (!light)
5708                         continue;
5709                 rtlight = &light->rtlight;
5710                 rtlight->corona_visibility = 0;
5711                 rtlight->corona_queryindex_visiblepixels = 0;
5712                 rtlight->corona_queryindex_allpixels = 0;
5713                 if (!(rtlight->flags & flag))
5714                         continue;
5715                 if (rtlight->corona <= 0)
5716                         continue;
5717                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5718                         continue;
5719                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5720         }
5721         for (i = 0;i < r_refdef.scene.numlights;i++)
5722         {
5723                 rtlight = r_refdef.scene.lights[i];
5724                 rtlight->corona_visibility = 0;
5725                 rtlight->corona_queryindex_visiblepixels = 0;
5726                 rtlight->corona_queryindex_allpixels = 0;
5727                 if (!(rtlight->flags & flag))
5728                         continue;
5729                 if (rtlight->corona <= 0)
5730                         continue;
5731                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5732         }
5733         if (usequery)
5734                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5735
5736         // now draw the coronas using the query data for intensity info
5737         for (lightindex = 0;lightindex < range;lightindex++)
5738         {
5739                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5740                 if (!light)
5741                         continue;
5742                 rtlight = &light->rtlight;
5743                 if (rtlight->corona_visibility <= 0)
5744                         continue;
5745                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5746         }
5747         for (i = 0;i < r_refdef.scene.numlights;i++)
5748         {
5749                 rtlight = r_refdef.scene.lights[i];
5750                 if (rtlight->corona_visibility <= 0)
5751                         continue;
5752                 if (gl_flashblend.integer)
5753                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5754                 else
5755                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5756         }
5757 }
5758
5759
5760
5761 static dlight_t *R_Shadow_NewWorldLight(void)
5762 {
5763         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5764 }
5765
5766 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)
5767 {
5768         matrix4x4_t matrix;
5769
5770         // 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
5771
5772         // validate parameters
5773         if (!cubemapname)
5774                 cubemapname = "";
5775
5776         // copy to light properties
5777         VectorCopy(origin, light->origin);
5778         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5779         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5780         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5781         /*
5782         light->color[0] = max(color[0], 0);
5783         light->color[1] = max(color[1], 0);
5784         light->color[2] = max(color[2], 0);
5785         */
5786         light->color[0] = color[0];
5787         light->color[1] = color[1];
5788         light->color[2] = color[2];
5789         light->radius = max(radius, 0);
5790         light->style = style;
5791         light->shadow = shadowenable;
5792         light->corona = corona;
5793         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5794         light->coronasizescale = coronasizescale;
5795         light->ambientscale = ambientscale;
5796         light->diffusescale = diffusescale;
5797         light->specularscale = specularscale;
5798         light->flags = flags;
5799
5800         // update renderable light data
5801         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5802         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);
5803 }
5804
5805 static void R_Shadow_FreeWorldLight(dlight_t *light)
5806 {
5807         if (r_shadow_selectedlight == light)
5808                 r_shadow_selectedlight = NULL;
5809         R_RTLight_Uncompile(&light->rtlight);
5810         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5811 }
5812
5813 void R_Shadow_ClearWorldLights(void)
5814 {
5815         size_t lightindex;
5816         dlight_t *light;
5817         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5818         for (lightindex = 0;lightindex < range;lightindex++)
5819         {
5820                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5821                 if (light)
5822                         R_Shadow_FreeWorldLight(light);
5823         }
5824         r_shadow_selectedlight = NULL;
5825 }
5826
5827 static void R_Shadow_SelectLight(dlight_t *light)
5828 {
5829         if (r_shadow_selectedlight)
5830                 r_shadow_selectedlight->selected = false;
5831         r_shadow_selectedlight = light;
5832         if (r_shadow_selectedlight)
5833                 r_shadow_selectedlight->selected = true;
5834 }
5835
5836 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5837 {
5838         // this is never batched (there can be only one)
5839         float vertex3f[12];
5840         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5841         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5842         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5843 }
5844
5845 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5846 {
5847         float intensity;
5848         float s;
5849         vec3_t spritecolor;
5850         skinframe_t *skinframe;
5851         float vertex3f[12];
5852
5853         // this is never batched (due to the ent parameter changing every time)
5854         // so numsurfaces == 1 and surfacelist[0] == lightnumber
5855         const dlight_t *light = (dlight_t *)ent;
5856         s = EDLIGHTSPRSIZE;
5857
5858         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5859
5860         intensity = 0.5f;
5861         VectorScale(light->color, intensity, spritecolor);
5862         if (VectorLength(spritecolor) < 0.1732f)
5863                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5864         if (VectorLength(spritecolor) > 1.0f)
5865                 VectorNormalize(spritecolor);
5866
5867         // draw light sprite
5868         if (light->cubemapname[0] && !light->shadow)
5869                 skinframe = r_editlights_sprcubemapnoshadowlight;
5870         else if (light->cubemapname[0])
5871                 skinframe = r_editlights_sprcubemaplight;
5872         else if (!light->shadow)
5873                 skinframe = r_editlights_sprnoshadowlight;
5874         else
5875                 skinframe = r_editlights_sprlight;
5876
5877         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);
5878         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5879
5880         // draw selection sprite if light is selected
5881         if (light->selected)
5882         {
5883                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5884                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5885                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5886         }
5887 }
5888
5889 void R_Shadow_DrawLightSprites(void)
5890 {
5891         size_t lightindex;
5892         dlight_t *light;
5893         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5894         for (lightindex = 0;lightindex < range;lightindex++)
5895         {
5896                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5897                 if (light)
5898                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5899         }
5900         if (!r_editlights_lockcursor)
5901                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5902 }
5903
5904 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5905 {
5906         unsigned int range;
5907         dlight_t *light;
5908         rtlight_t *rtlight;
5909         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5910         if (lightindex >= range)
5911                 return -1;
5912         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5913         if (!light)
5914                 return 0;
5915         rtlight = &light->rtlight;
5916         //if (!(rtlight->flags & flag))
5917         //      return 0;
5918         VectorCopy(rtlight->shadoworigin, origin);
5919         *radius = rtlight->radius;
5920         VectorCopy(rtlight->color, color);
5921         return 1;
5922 }
5923
5924 static void R_Shadow_SelectLightInView(void)
5925 {
5926         float bestrating, rating, temp[3];
5927         dlight_t *best;
5928         size_t lightindex;
5929         dlight_t *light;
5930         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5931         best = NULL;
5932         bestrating = 0;
5933
5934         if (r_editlights_lockcursor)
5935                 return;
5936         for (lightindex = 0;lightindex < range;lightindex++)
5937         {
5938                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5939                 if (!light)
5940                         continue;
5941                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5942                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5943                 if (rating >= 0.95)
5944                 {
5945                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5946                         if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
5947                         {
5948                                 bestrating = rating;
5949                                 best = light;
5950                         }
5951                 }
5952         }
5953         R_Shadow_SelectLight(best);
5954 }
5955
5956 void R_Shadow_LoadWorldLights(void)
5957 {
5958         int n, a, style, shadow, flags;
5959         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5960         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5961         if (cl.worldmodel == NULL)
5962         {
5963                 Con_Print("No map loaded.\n");
5964                 return;
5965         }
5966         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5967         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5968         if (lightsstring)
5969         {
5970                 s = lightsstring;
5971                 n = 0;
5972                 while (*s)
5973                 {
5974                         /*
5975                         t = s;
5976                         shadow = true;
5977                         for (;COM_Parse(t, true) && strcmp(
5978                         if (COM_Parse(t, true))
5979                         {
5980                                 if (com_token[0] == '!')
5981                                 {
5982                                         shadow = false;
5983                                         origin[0] = atof(com_token+1);
5984                                 }
5985                                 else
5986                                         origin[0] = atof(com_token);
5987                                 if (Com_Parse(t
5988                         }
5989                         */
5990                         t = s;
5991                         while (*s && *s != '\n' && *s != '\r')
5992                                 s++;
5993                         if (!*s)
5994                                 break;
5995                         tempchar = *s;
5996                         shadow = true;
5997                         // check for modifier flags
5998                         if (*t == '!')
5999                         {
6000                                 shadow = false;
6001                                 t++;
6002                         }
6003                         *s = 0;
6004 #if _MSC_VER >= 1400
6005 #define sscanf sscanf_s
6006 #endif
6007                         cubemapname[sizeof(cubemapname)-1] = 0;
6008 #if MAX_QPATH != 128
6009 #error update this code if MAX_QPATH changes
6010 #endif
6011                         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
6012 #if _MSC_VER >= 1400
6013 , sizeof(cubemapname)
6014 #endif
6015 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
6016                         *s = tempchar;
6017                         if (a < 18)
6018                                 flags = LIGHTFLAG_REALTIMEMODE;
6019                         if (a < 17)
6020                                 specularscale = 1;
6021                         if (a < 16)
6022                                 diffusescale = 1;
6023                         if (a < 15)
6024                                 ambientscale = 0;
6025                         if (a < 14)
6026                                 coronasizescale = 0.25f;
6027                         if (a < 13)
6028                                 VectorClear(angles);
6029                         if (a < 10)
6030                                 corona = 0;
6031                         if (a < 9 || !strcmp(cubemapname, "\"\""))
6032                                 cubemapname[0] = 0;
6033                         // remove quotes on cubemapname
6034                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
6035                         {
6036                                 size_t namelen;
6037                                 namelen = strlen(cubemapname) - 2;
6038                                 memmove(cubemapname, cubemapname + 1, namelen);
6039                                 cubemapname[namelen] = '\0';
6040                         }
6041                         if (a < 8)
6042                         {
6043                                 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);
6044                                 break;
6045                         }
6046                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6047                         if (*s == '\r')
6048                                 s++;
6049                         if (*s == '\n')
6050                                 s++;
6051                         n++;
6052                 }
6053                 if (*s)
6054                         Con_Printf("invalid rtlights file \"%s\"\n", name);
6055                 Mem_Free(lightsstring);
6056         }
6057 }
6058
6059 void R_Shadow_SaveWorldLights(void)
6060 {
6061         size_t lightindex;
6062         dlight_t *light;
6063         size_t bufchars, bufmaxchars;
6064         char *buf, *oldbuf;
6065         char name[MAX_QPATH];
6066         char line[MAX_INPUTLINE];
6067         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
6068         // I hate lines which are 3 times my screen size :( --blub
6069         if (!range)
6070                 return;
6071         if (cl.worldmodel == NULL)
6072         {
6073                 Con_Print("No map loaded.\n");
6074                 return;
6075         }
6076         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
6077         bufchars = bufmaxchars = 0;
6078         buf = NULL;
6079         for (lightindex = 0;lightindex < range;lightindex++)
6080         {
6081                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6082                 if (!light)
6083                         continue;
6084                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
6085                         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);
6086                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
6087                         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]);
6088                 else
6089                         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);
6090                 if (bufchars + strlen(line) > bufmaxchars)
6091                 {
6092                         bufmaxchars = bufchars + strlen(line) + 2048;
6093                         oldbuf = buf;
6094                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
6095                         if (oldbuf)
6096                         {
6097                                 if (bufchars)
6098                                         memcpy(buf, oldbuf, bufchars);
6099                                 Mem_Free(oldbuf);
6100                         }
6101                 }
6102                 if (strlen(line))
6103                 {
6104                         memcpy(buf + bufchars, line, strlen(line));
6105                         bufchars += strlen(line);
6106                 }
6107         }
6108         if (bufchars)
6109                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
6110         if (buf)
6111                 Mem_Free(buf);
6112 }
6113
6114 void R_Shadow_LoadLightsFile(void)
6115 {
6116         int n, a, style;
6117         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
6118         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
6119         if (cl.worldmodel == NULL)
6120         {
6121                 Con_Print("No map loaded.\n");
6122                 return;
6123         }
6124         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
6125         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
6126         if (lightsstring)
6127         {
6128                 s = lightsstring;
6129                 n = 0;
6130                 while (*s)
6131                 {
6132                         t = s;
6133                         while (*s && *s != '\n' && *s != '\r')
6134                                 s++;
6135                         if (!*s)
6136                                 break;
6137                         tempchar = *s;
6138                         *s = 0;
6139                         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);
6140                         *s = tempchar;
6141                         if (a < 14)
6142                         {
6143                                 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);
6144                                 break;
6145                         }
6146                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
6147                         radius = bound(15, radius, 4096);
6148                         VectorScale(color, (2.0f / (8388608.0f)), color);
6149                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6150                         if (*s == '\r')
6151                                 s++;
6152                         if (*s == '\n')
6153                                 s++;
6154                         n++;
6155                 }
6156                 if (*s)
6157                         Con_Printf("invalid lights file \"%s\"\n", name);
6158                 Mem_Free(lightsstring);
6159         }
6160 }
6161
6162 // tyrlite/hmap2 light types in the delay field
6163 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
6164
6165 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
6166 {
6167         int entnum;
6168         int style;
6169         int islight;
6170         int skin;
6171         int pflags;
6172         //int effects;
6173         int type;
6174         int n;
6175         char *entfiledata;
6176         const char *data;
6177         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
6178         char key[256], value[MAX_INPUTLINE];
6179         char vabuf[1024];
6180
6181         if (cl.worldmodel == NULL)
6182         {
6183                 Con_Print("No map loaded.\n");
6184                 return;
6185         }
6186         // try to load a .ent file first
6187         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
6188         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
6189         // and if that is not found, fall back to the bsp file entity string
6190         if (!data)
6191                 data = cl.worldmodel->brush.entities;
6192         if (!data)
6193                 return;
6194         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
6195         {
6196                 type = LIGHTTYPE_MINUSX;
6197                 origin[0] = origin[1] = origin[2] = 0;
6198                 originhack[0] = originhack[1] = originhack[2] = 0;
6199                 angles[0] = angles[1] = angles[2] = 0;
6200                 color[0] = color[1] = color[2] = 1;
6201                 light[0] = light[1] = light[2] = 1;light[3] = 300;
6202                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
6203                 fadescale = 1;
6204                 lightscale = 1;
6205                 style = 0;
6206                 skin = 0;
6207                 pflags = 0;
6208                 //effects = 0;
6209                 islight = false;
6210                 while (1)
6211                 {
6212                         if (!COM_ParseToken_Simple(&data, false, false, true))
6213                                 break; // error
6214                         if (com_token[0] == '}')
6215                                 break; // end of entity
6216                         if (com_token[0] == '_')
6217                                 strlcpy(key, com_token + 1, sizeof(key));
6218                         else
6219                                 strlcpy(key, com_token, sizeof(key));
6220                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
6221                                 key[strlen(key)-1] = 0;
6222                         if (!COM_ParseToken_Simple(&data, false, false, true))
6223                                 break; // error
6224                         strlcpy(value, com_token, sizeof(value));
6225
6226                         // now that we have the key pair worked out...
6227                         if (!strcmp("light", key))
6228                         {
6229                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
6230                                 if (n == 1)
6231                                 {
6232                                         // quake
6233                                         light[0] = vec[0] * (1.0f / 256.0f);
6234                                         light[1] = vec[0] * (1.0f / 256.0f);
6235                                         light[2] = vec[0] * (1.0f / 256.0f);
6236                                         light[3] = vec[0];
6237                                 }
6238                                 else if (n == 4)
6239                                 {
6240                                         // halflife
6241                                         light[0] = vec[0] * (1.0f / 255.0f);
6242                                         light[1] = vec[1] * (1.0f / 255.0f);
6243                                         light[2] = vec[2] * (1.0f / 255.0f);
6244                                         light[3] = vec[3];
6245                                 }
6246                         }
6247                         else if (!strcmp("delay", key))
6248                                 type = atoi(value);
6249                         else if (!strcmp("origin", key))
6250                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
6251                         else if (!strcmp("angle", key))
6252                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
6253                         else if (!strcmp("angles", key))
6254                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
6255                         else if (!strcmp("color", key))
6256                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
6257                         else if (!strcmp("wait", key))
6258                                 fadescale = atof(value);
6259                         else if (!strcmp("classname", key))
6260                         {
6261                                 if (!strncmp(value, "light", 5))
6262                                 {
6263                                         islight = true;
6264                                         if (!strcmp(value, "light_fluoro"))
6265                                         {
6266                                                 originhack[0] = 0;
6267                                                 originhack[1] = 0;
6268                                                 originhack[2] = 0;
6269                                                 overridecolor[0] = 1;
6270                                                 overridecolor[1] = 1;
6271                                                 overridecolor[2] = 1;
6272                                         }
6273                                         if (!strcmp(value, "light_fluorospark"))
6274                                         {
6275                                                 originhack[0] = 0;
6276                                                 originhack[1] = 0;
6277                                                 originhack[2] = 0;
6278                                                 overridecolor[0] = 1;
6279                                                 overridecolor[1] = 1;
6280                                                 overridecolor[2] = 1;
6281                                         }
6282                                         if (!strcmp(value, "light_globe"))
6283                                         {
6284                                                 originhack[0] = 0;
6285                                                 originhack[1] = 0;
6286                                                 originhack[2] = 0;
6287                                                 overridecolor[0] = 1;
6288                                                 overridecolor[1] = 0.8;
6289                                                 overridecolor[2] = 0.4;
6290                                         }
6291                                         if (!strcmp(value, "light_flame_large_yellow"))
6292                                         {
6293                                                 originhack[0] = 0;
6294                                                 originhack[1] = 0;
6295                                                 originhack[2] = 0;
6296                                                 overridecolor[0] = 1;
6297                                                 overridecolor[1] = 0.5;
6298                                                 overridecolor[2] = 0.1;
6299                                         }
6300                                         if (!strcmp(value, "light_flame_small_yellow"))
6301                                         {
6302                                                 originhack[0] = 0;
6303                                                 originhack[1] = 0;
6304                                                 originhack[2] = 0;
6305                                                 overridecolor[0] = 1;
6306                                                 overridecolor[1] = 0.5;
6307                                                 overridecolor[2] = 0.1;
6308                                         }
6309                                         if (!strcmp(value, "light_torch_small_white"))
6310                                         {
6311                                                 originhack[0] = 0;
6312                                                 originhack[1] = 0;
6313                                                 originhack[2] = 0;
6314                                                 overridecolor[0] = 1;
6315                                                 overridecolor[1] = 0.5;
6316                                                 overridecolor[2] = 0.1;
6317                                         }
6318                                         if (!strcmp(value, "light_torch_small_walltorch"))
6319                                         {
6320                                                 originhack[0] = 0;
6321                                                 originhack[1] = 0;
6322                                                 originhack[2] = 0;
6323                                                 overridecolor[0] = 1;
6324                                                 overridecolor[1] = 0.5;
6325                                                 overridecolor[2] = 0.1;
6326                                         }
6327                                 }
6328                         }
6329                         else if (!strcmp("style", key))
6330                                 style = atoi(value);
6331                         else if (!strcmp("skin", key))
6332                                 skin = (int)atof(value);
6333                         else if (!strcmp("pflags", key))
6334                                 pflags = (int)atof(value);
6335                         //else if (!strcmp("effects", key))
6336                         //      effects = (int)atof(value);
6337                         else if (cl.worldmodel->type == mod_brushq3)
6338                         {
6339                                 if (!strcmp("scale", key))
6340                                         lightscale = atof(value);
6341                                 if (!strcmp("fade", key))
6342                                         fadescale = atof(value);
6343                         }
6344                 }
6345                 if (!islight)
6346                         continue;
6347                 if (lightscale <= 0)
6348                         lightscale = 1;
6349                 if (fadescale <= 0)
6350                         fadescale = 1;
6351                 if (color[0] == color[1] && color[0] == color[2])
6352                 {
6353                         color[0] *= overridecolor[0];
6354                         color[1] *= overridecolor[1];
6355                         color[2] *= overridecolor[2];
6356                 }
6357                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
6358                 color[0] = color[0] * light[0];
6359                 color[1] = color[1] * light[1];
6360                 color[2] = color[2] * light[2];
6361                 switch (type)
6362                 {
6363                 case LIGHTTYPE_MINUSX:
6364                         break;
6365                 case LIGHTTYPE_RECIPX:
6366                         radius *= 2;
6367                         VectorScale(color, (1.0f / 16.0f), color);
6368                         break;
6369                 case LIGHTTYPE_RECIPXX:
6370                         radius *= 2;
6371                         VectorScale(color, (1.0f / 16.0f), color);
6372                         break;
6373                 default:
6374                 case LIGHTTYPE_NONE:
6375                         break;
6376                 case LIGHTTYPE_SUN:
6377                         break;
6378                 case LIGHTTYPE_MINUSXX:
6379                         break;
6380                 }
6381                 VectorAdd(origin, originhack, origin);
6382                 if (radius >= 1)
6383                         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);
6384         }
6385         if (entfiledata)
6386                 Mem_Free(entfiledata);
6387 }
6388
6389
6390 static void R_Shadow_SetCursorLocationForView(void)
6391 {
6392         vec_t dist, push;
6393         vec3_t dest, endpos;
6394         trace_t trace;
6395         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6396         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
6397         if (trace.fraction < 1)
6398         {
6399                 dist = trace.fraction * r_editlights_cursordistance.value;
6400                 push = r_editlights_cursorpushback.value;
6401                 if (push > dist)
6402                         push = dist;
6403                 push = -push;
6404                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6405                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6406         }
6407         else
6408         {
6409                 VectorClear( endpos );
6410         }
6411         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6412         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6413         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6414 }
6415
6416 void R_Shadow_UpdateWorldLightSelection(void)
6417 {
6418         if (r_editlights.integer)
6419         {
6420                 R_Shadow_SetCursorLocationForView();
6421                 R_Shadow_SelectLightInView();
6422         }
6423         else
6424                 R_Shadow_SelectLight(NULL);
6425 }
6426
6427 static void R_Shadow_EditLights_Clear_f(void)
6428 {
6429         R_Shadow_ClearWorldLights();
6430 }
6431
6432 void R_Shadow_EditLights_Reload_f(void)
6433 {
6434         if (!cl.worldmodel)
6435                 return;
6436         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6437         R_Shadow_ClearWorldLights();
6438         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6439         {
6440                 R_Shadow_LoadWorldLights();
6441                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6442                         R_Shadow_LoadLightsFile();
6443         }
6444         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6445         {
6446                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6447                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6448         }
6449 }
6450
6451 static void R_Shadow_EditLights_Save_f(void)
6452 {
6453         if (!cl.worldmodel)
6454                 return;
6455         R_Shadow_SaveWorldLights();
6456 }
6457
6458 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6459 {
6460         R_Shadow_ClearWorldLights();
6461         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6462 }
6463
6464 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6465 {
6466         R_Shadow_ClearWorldLights();
6467         R_Shadow_LoadLightsFile();
6468 }
6469
6470 static void R_Shadow_EditLights_Spawn_f(void)
6471 {
6472         vec3_t color;
6473         if (!r_editlights.integer)
6474         {
6475                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6476                 return;
6477         }
6478         if (Cmd_Argc() != 1)
6479         {
6480                 Con_Print("r_editlights_spawn does not take parameters\n");
6481                 return;
6482         }
6483         color[0] = color[1] = color[2] = 1;
6484         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6485 }
6486
6487 static void R_Shadow_EditLights_Edit_f(void)
6488 {
6489         vec3_t origin, angles, color;
6490         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6491         int style, shadows, flags, normalmode, realtimemode;
6492         char cubemapname[MAX_INPUTLINE];
6493         if (!r_editlights.integer)
6494         {
6495                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6496                 return;
6497         }
6498         if (!r_shadow_selectedlight)
6499         {
6500                 Con_Print("No selected light.\n");
6501                 return;
6502         }
6503         VectorCopy(r_shadow_selectedlight->origin, origin);
6504         VectorCopy(r_shadow_selectedlight->angles, angles);
6505         VectorCopy(r_shadow_selectedlight->color, color);
6506         radius = r_shadow_selectedlight->radius;
6507         style = r_shadow_selectedlight->style;
6508         if (r_shadow_selectedlight->cubemapname)
6509                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6510         else
6511                 cubemapname[0] = 0;
6512         shadows = r_shadow_selectedlight->shadow;
6513         corona = r_shadow_selectedlight->corona;
6514         coronasizescale = r_shadow_selectedlight->coronasizescale;
6515         ambientscale = r_shadow_selectedlight->ambientscale;
6516         diffusescale = r_shadow_selectedlight->diffusescale;
6517         specularscale = r_shadow_selectedlight->specularscale;
6518         flags = r_shadow_selectedlight->flags;
6519         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6520         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6521         if (!strcmp(Cmd_Argv(1), "origin"))
6522         {
6523                 if (Cmd_Argc() != 5)
6524                 {
6525                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6526                         return;
6527                 }
6528                 origin[0] = atof(Cmd_Argv(2));
6529                 origin[1] = atof(Cmd_Argv(3));
6530                 origin[2] = atof(Cmd_Argv(4));
6531         }
6532         else if (!strcmp(Cmd_Argv(1), "originscale"))
6533         {
6534                 if (Cmd_Argc() != 5)
6535                 {
6536                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6537                         return;
6538                 }
6539                 origin[0] *= atof(Cmd_Argv(2));
6540                 origin[1] *= atof(Cmd_Argv(3));
6541                 origin[2] *= atof(Cmd_Argv(4));
6542         }
6543         else if (!strcmp(Cmd_Argv(1), "originx"))
6544         {
6545                 if (Cmd_Argc() != 3)
6546                 {
6547                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6548                         return;
6549                 }
6550                 origin[0] = atof(Cmd_Argv(2));
6551         }
6552         else if (!strcmp(Cmd_Argv(1), "originy"))
6553         {
6554                 if (Cmd_Argc() != 3)
6555                 {
6556                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6557                         return;
6558                 }
6559                 origin[1] = atof(Cmd_Argv(2));
6560         }
6561         else if (!strcmp(Cmd_Argv(1), "originz"))
6562         {
6563                 if (Cmd_Argc() != 3)
6564                 {
6565                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6566                         return;
6567                 }
6568                 origin[2] = atof(Cmd_Argv(2));
6569         }
6570         else if (!strcmp(Cmd_Argv(1), "move"))
6571         {
6572                 if (Cmd_Argc() != 5)
6573                 {
6574                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6575                         return;
6576                 }
6577                 origin[0] += atof(Cmd_Argv(2));
6578                 origin[1] += atof(Cmd_Argv(3));
6579                 origin[2] += atof(Cmd_Argv(4));
6580         }
6581         else if (!strcmp(Cmd_Argv(1), "movex"))
6582         {
6583                 if (Cmd_Argc() != 3)
6584                 {
6585                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6586                         return;
6587                 }
6588                 origin[0] += atof(Cmd_Argv(2));
6589         }
6590         else if (!strcmp(Cmd_Argv(1), "movey"))
6591         {
6592                 if (Cmd_Argc() != 3)
6593                 {
6594                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6595                         return;
6596                 }
6597                 origin[1] += atof(Cmd_Argv(2));
6598         }
6599         else if (!strcmp(Cmd_Argv(1), "movez"))
6600         {
6601                 if (Cmd_Argc() != 3)
6602                 {
6603                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6604                         return;
6605                 }
6606                 origin[2] += atof(Cmd_Argv(2));
6607         }
6608         else if (!strcmp(Cmd_Argv(1), "angles"))
6609         {
6610                 if (Cmd_Argc() != 5)
6611                 {
6612                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6613                         return;
6614                 }
6615                 angles[0] = atof(Cmd_Argv(2));
6616                 angles[1] = atof(Cmd_Argv(3));
6617                 angles[2] = atof(Cmd_Argv(4));
6618         }
6619         else if (!strcmp(Cmd_Argv(1), "anglesx"))
6620         {
6621                 if (Cmd_Argc() != 3)
6622                 {
6623                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6624                         return;
6625                 }
6626                 angles[0] = atof(Cmd_Argv(2));
6627         }
6628         else if (!strcmp(Cmd_Argv(1), "anglesy"))
6629         {
6630                 if (Cmd_Argc() != 3)
6631                 {
6632                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6633                         return;
6634                 }
6635                 angles[1] = atof(Cmd_Argv(2));
6636         }
6637         else if (!strcmp(Cmd_Argv(1), "anglesz"))
6638         {
6639                 if (Cmd_Argc() != 3)
6640                 {
6641                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6642                         return;
6643                 }
6644                 angles[2] = atof(Cmd_Argv(2));
6645         }
6646         else if (!strcmp(Cmd_Argv(1), "color"))
6647         {
6648                 if (Cmd_Argc() != 5)
6649                 {
6650                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6651                         return;
6652                 }
6653                 color[0] = atof(Cmd_Argv(2));
6654                 color[1] = atof(Cmd_Argv(3));
6655                 color[2] = atof(Cmd_Argv(4));
6656         }
6657         else if (!strcmp(Cmd_Argv(1), "radius"))
6658         {
6659                 if (Cmd_Argc() != 3)
6660                 {
6661                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6662                         return;
6663                 }
6664                 radius = atof(Cmd_Argv(2));
6665         }
6666         else if (!strcmp(Cmd_Argv(1), "colorscale"))
6667         {
6668                 if (Cmd_Argc() == 3)
6669                 {
6670                         double scale = atof(Cmd_Argv(2));
6671                         color[0] *= scale;
6672                         color[1] *= scale;
6673                         color[2] *= scale;
6674                 }
6675                 else
6676                 {
6677                         if (Cmd_Argc() != 5)
6678                         {
6679                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(1));
6680                                 return;
6681                         }
6682                         color[0] *= atof(Cmd_Argv(2));
6683                         color[1] *= atof(Cmd_Argv(3));
6684                         color[2] *= atof(Cmd_Argv(4));
6685                 }
6686         }
6687         else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6688         {
6689                 if (Cmd_Argc() != 3)
6690                 {
6691                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6692                         return;
6693                 }
6694                 radius *= atof(Cmd_Argv(2));
6695         }
6696         else if (!strcmp(Cmd_Argv(1), "style"))
6697         {
6698                 if (Cmd_Argc() != 3)
6699                 {
6700                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6701                         return;
6702                 }
6703                 style = atoi(Cmd_Argv(2));
6704         }
6705         else if (!strcmp(Cmd_Argv(1), "cubemap"))
6706         {
6707                 if (Cmd_Argc() > 3)
6708                 {
6709                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6710                         return;
6711                 }
6712                 if (Cmd_Argc() == 3)
6713                         strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6714                 else
6715                         cubemapname[0] = 0;
6716         }
6717         else if (!strcmp(Cmd_Argv(1), "shadows"))
6718         {
6719                 if (Cmd_Argc() != 3)
6720                 {
6721                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6722                         return;
6723                 }
6724                 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6725         }
6726         else if (!strcmp(Cmd_Argv(1), "corona"))
6727         {
6728                 if (Cmd_Argc() != 3)
6729                 {
6730                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6731                         return;
6732                 }
6733                 corona = atof(Cmd_Argv(2));
6734         }
6735         else if (!strcmp(Cmd_Argv(1), "coronasize"))
6736         {
6737                 if (Cmd_Argc() != 3)
6738                 {
6739                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6740                         return;
6741                 }
6742                 coronasizescale = atof(Cmd_Argv(2));
6743         }
6744         else if (!strcmp(Cmd_Argv(1), "ambient"))
6745         {
6746                 if (Cmd_Argc() != 3)
6747                 {
6748                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6749                         return;
6750                 }
6751                 ambientscale = atof(Cmd_Argv(2));
6752         }
6753         else if (!strcmp(Cmd_Argv(1), "diffuse"))
6754         {
6755                 if (Cmd_Argc() != 3)
6756                 {
6757                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6758                         return;
6759                 }
6760                 diffusescale = atof(Cmd_Argv(2));
6761         }
6762         else if (!strcmp(Cmd_Argv(1), "specular"))
6763         {
6764                 if (Cmd_Argc() != 3)
6765                 {
6766                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6767                         return;
6768                 }
6769                 specularscale = atof(Cmd_Argv(2));
6770         }
6771         else if (!strcmp(Cmd_Argv(1), "normalmode"))
6772         {
6773                 if (Cmd_Argc() != 3)
6774                 {
6775                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6776                         return;
6777                 }
6778                 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6779         }
6780         else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6781         {
6782                 if (Cmd_Argc() != 3)
6783                 {
6784                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6785                         return;
6786                 }
6787                 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6788         }
6789         else
6790         {
6791                 Con_Print("usage: r_editlights_edit [property] [value]\n");
6792                 Con_Print("Selected light's properties:\n");
6793                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6794                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6795                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6796                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
6797                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
6798                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
6799                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6800                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
6801                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
6802                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
6803                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
6804                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
6805                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6806                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6807                 return;
6808         }
6809         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6810         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6811 }
6812
6813 static void R_Shadow_EditLights_EditAll_f(void)
6814 {
6815         size_t lightindex;
6816         dlight_t *light, *oldselected;
6817         size_t range;
6818
6819         if (!r_editlights.integer)
6820         {
6821                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6822                 return;
6823         }
6824
6825         oldselected = r_shadow_selectedlight;
6826         // EditLights doesn't seem to have a "remove" command or something so:
6827         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6828         for (lightindex = 0;lightindex < range;lightindex++)
6829         {
6830                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6831                 if (!light)
6832                         continue;
6833                 R_Shadow_SelectLight(light);
6834                 R_Shadow_EditLights_Edit_f();
6835         }
6836         // return to old selected (to not mess editing once selection is locked)
6837         R_Shadow_SelectLight(oldselected);
6838 }
6839
6840 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6841 {
6842         int lightnumber, lightcount;
6843         size_t lightindex, range;
6844         dlight_t *light;
6845         char temp[256];
6846         float x, y;
6847
6848         if (!r_editlights.integer)
6849                 return;
6850
6851         // update cvars so QC can query them
6852         if (r_shadow_selectedlight)
6853         {
6854                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6855                 Cvar_SetQuick(&r_editlights_current_origin, temp);
6856                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6857                 Cvar_SetQuick(&r_editlights_current_angles, temp);
6858                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6859                 Cvar_SetQuick(&r_editlights_current_color, temp);
6860                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6861                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6862                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6863                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6864                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6865                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6866                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6867                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6868                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6869                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6870                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6871         }
6872
6873         // draw properties on screen
6874         if (!r_editlights_drawproperties.integer)
6875                 return;
6876         x = vid_conwidth.value - 240;
6877         y = 5;
6878         DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6879         lightnumber = -1;
6880         lightcount = 0;
6881         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6882         for (lightindex = 0;lightindex < range;lightindex++)
6883         {
6884                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6885                 if (!light)
6886                         continue;
6887                 if (light == r_shadow_selectedlight)
6888                         lightnumber = (int)lightindex;
6889                 lightcount++;
6890         }
6891         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;
6892         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;
6893         y += 8;
6894         if (r_shadow_selectedlight == NULL)
6895                 return;
6896         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;
6897         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;
6898         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;
6899         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;
6900         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;
6901         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;
6902         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;
6903         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;
6904         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;
6905         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;
6906         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;
6907         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;
6908         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;
6909         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;
6910         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;
6911 }
6912
6913 static void R_Shadow_EditLights_ToggleShadow_f(void)
6914 {
6915         if (!r_editlights.integer)
6916         {
6917                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6918                 return;
6919         }
6920         if (!r_shadow_selectedlight)
6921         {
6922                 Con_Print("No selected light.\n");
6923                 return;
6924         }
6925         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);
6926 }
6927
6928 static void R_Shadow_EditLights_ToggleCorona_f(void)
6929 {
6930         if (!r_editlights.integer)
6931         {
6932                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
6933                 return;
6934         }
6935         if (!r_shadow_selectedlight)
6936         {
6937                 Con_Print("No selected light.\n");
6938                 return;
6939         }
6940         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);
6941 }
6942
6943 static void R_Shadow_EditLights_Remove_f(void)
6944 {
6945         if (!r_editlights.integer)
6946         {
6947                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
6948                 return;
6949         }
6950         if (!r_shadow_selectedlight)
6951         {
6952                 Con_Print("No selected light.\n");
6953                 return;
6954         }
6955         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6956         r_shadow_selectedlight = NULL;
6957 }
6958
6959 static void R_Shadow_EditLights_Help_f(void)
6960 {
6961         Con_Print(
6962 "Documentation on r_editlights system:\n"
6963 "Settings:\n"
6964 "r_editlights : enable/disable editing mode\n"
6965 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6966 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6967 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6968 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6969 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6970 "Commands:\n"
6971 "r_editlights_help : this help\n"
6972 "r_editlights_clear : remove all lights\n"
6973 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6974 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6975 "r_editlights_save : save to .rtlights file\n"
6976 "r_editlights_spawn : create a light with default settings\n"
6977 "r_editlights_edit command : edit selected light - more documentation below\n"
6978 "r_editlights_remove : remove selected light\n"
6979 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6980 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6981 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6982 "Edit commands:\n"
6983 "origin x y z : set light location\n"
6984 "originx x: set x component of light location\n"
6985 "originy y: set y component of light location\n"
6986 "originz z: set z component of light location\n"
6987 "move x y z : adjust light location\n"
6988 "movex x: adjust x component of light location\n"
6989 "movey y: adjust y component of light location\n"
6990 "movez z: adjust z component of light location\n"
6991 "angles x y z : set light angles\n"
6992 "anglesx x: set x component of light angles\n"
6993 "anglesy y: set y component of light angles\n"
6994 "anglesz z: set z component of light angles\n"
6995 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6996 "radius radius : set radius (size) of light\n"
6997 "colorscale grey : multiply color of light (1 does nothing)\n"
6998 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6999 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
7000 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
7001 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
7002 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
7003 "cubemap basename : set filter cubemap of light\n"
7004 "shadows 1/0 : turn on/off shadows\n"
7005 "corona n : set corona intensity\n"
7006 "coronasize n : set corona size (0-1)\n"
7007 "ambient n : set ambient intensity (0-1)\n"
7008 "diffuse n : set diffuse intensity (0-1)\n"
7009 "specular n : set specular intensity (0-1)\n"
7010 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
7011 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
7012 "<nothing> : print light properties to console\n"
7013         );
7014 }
7015
7016 static void R_Shadow_EditLights_CopyInfo_f(void)
7017 {
7018         if (!r_editlights.integer)
7019         {
7020                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
7021                 return;
7022         }
7023         if (!r_shadow_selectedlight)
7024         {
7025                 Con_Print("No selected light.\n");
7026                 return;
7027         }
7028         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
7029         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
7030         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
7031         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
7032         if (r_shadow_selectedlight->cubemapname)
7033                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
7034         else
7035                 r_shadow_bufferlight.cubemapname[0] = 0;
7036         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
7037         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
7038         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
7039         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
7040         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
7041         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
7042         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
7043 }
7044
7045 static void R_Shadow_EditLights_PasteInfo_f(void)
7046 {
7047         if (!r_editlights.integer)
7048         {
7049                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
7050                 return;
7051         }
7052         if (!r_shadow_selectedlight)
7053         {
7054                 Con_Print("No selected light.\n");
7055                 return;
7056         }
7057         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);
7058 }
7059
7060 static void R_Shadow_EditLights_Lock_f(void)
7061 {
7062         if (!r_editlights.integer)
7063         {
7064                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
7065                 return;
7066         }
7067         if (r_editlights_lockcursor)
7068         {
7069                 r_editlights_lockcursor = false;
7070                 return;
7071         }
7072         if (!r_shadow_selectedlight)
7073         {
7074                 Con_Print("No selected light to lock on.\n");
7075                 return;
7076         }
7077         r_editlights_lockcursor = true;
7078 }
7079
7080 static void R_Shadow_EditLights_Init(void)
7081 {
7082         Cvar_RegisterVariable(&r_editlights);
7083         Cvar_RegisterVariable(&r_editlights_cursordistance);
7084         Cvar_RegisterVariable(&r_editlights_cursorpushback);
7085         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
7086         Cvar_RegisterVariable(&r_editlights_cursorgrid);
7087         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
7088         Cvar_RegisterVariable(&r_editlights_drawproperties);
7089         Cvar_RegisterVariable(&r_editlights_current_origin);
7090         Cvar_RegisterVariable(&r_editlights_current_angles);
7091         Cvar_RegisterVariable(&r_editlights_current_color);
7092         Cvar_RegisterVariable(&r_editlights_current_radius);
7093         Cvar_RegisterVariable(&r_editlights_current_corona);
7094         Cvar_RegisterVariable(&r_editlights_current_coronasize);
7095         Cvar_RegisterVariable(&r_editlights_current_style);
7096         Cvar_RegisterVariable(&r_editlights_current_shadows);
7097         Cvar_RegisterVariable(&r_editlights_current_cubemap);
7098         Cvar_RegisterVariable(&r_editlights_current_ambient);
7099         Cvar_RegisterVariable(&r_editlights_current_diffuse);
7100         Cvar_RegisterVariable(&r_editlights_current_specular);
7101         Cvar_RegisterVariable(&r_editlights_current_normalmode);
7102         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
7103         Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
7104         Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
7105         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)");
7106         Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
7107         Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
7108         Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
7109         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)");
7110         Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
7111         Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
7112         Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
7113         Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
7114         Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
7115         Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
7116         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)");
7117         Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
7118 }
7119
7120
7121
7122 /*
7123 =============================================================================
7124
7125 LIGHT SAMPLING
7126
7127 =============================================================================
7128 */
7129
7130 void R_LightPoint(float *color, const vec3_t p, const int flags)
7131 {
7132         int i, numlights, flag;
7133         float f, relativepoint[3], dist, dist2, lightradius2;
7134         vec3_t diffuse, n;
7135         rtlight_t *light;
7136         dlight_t *dlight;
7137
7138         if (r_fullbright.integer)
7139         {
7140                 VectorSet(color, 1, 1, 1);
7141                 return;
7142         }
7143
7144         VectorClear(color);
7145
7146         if (flags & LP_LIGHTMAP)
7147         {
7148                 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7149                 {
7150                         VectorClear(diffuse);
7151                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
7152                         VectorAdd(color, diffuse, color);
7153                 }
7154                 else
7155                         VectorSet(color, 1, 1, 1);
7156                 color[0] += r_refdef.scene.ambient;
7157                 color[1] += r_refdef.scene.ambient;
7158                 color[2] += r_refdef.scene.ambient;
7159         }
7160
7161         if (flags & LP_RTWORLD)
7162         {
7163                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7164                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7165                 for (i = 0; i < numlights; i++)
7166                 {
7167                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7168                         if (!dlight)
7169                                 continue;
7170                         light = &dlight->rtlight;
7171                         if (!(light->flags & flag))
7172                                 continue;
7173                         // sample
7174                         lightradius2 = light->radius * light->radius;
7175                         VectorSubtract(light->shadoworigin, p, relativepoint);
7176                         dist2 = VectorLength2(relativepoint);
7177                         if (dist2 >= lightradius2)
7178                                 continue;
7179                         dist = sqrt(dist2) / light->radius;
7180                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7181                         if (f <= 0)
7182                                 continue;
7183                         // todo: add to both ambient and diffuse
7184                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7185                                 VectorMA(color, f, light->currentcolor, color);
7186                 }
7187         }
7188         if (flags & LP_DYNLIGHT)
7189         {
7190                 // sample dlights
7191                 for (i = 0;i < r_refdef.scene.numlights;i++)
7192                 {
7193                         light = r_refdef.scene.lights[i];
7194                         // sample
7195                         lightradius2 = light->radius * light->radius;
7196                         VectorSubtract(light->shadoworigin, p, relativepoint);
7197                         dist2 = VectorLength2(relativepoint);
7198                         if (dist2 >= lightradius2)
7199                                 continue;
7200                         dist = sqrt(dist2) / light->radius;
7201                         f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
7202                         if (f <= 0)
7203                                 continue;
7204                         // todo: add to both ambient and diffuse
7205                         if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
7206                                 VectorMA(color, f, light->color, color);
7207                 }
7208         }
7209 }
7210
7211 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
7212 {
7213         int i, numlights, flag;
7214         rtlight_t *light;
7215         dlight_t *dlight;
7216         float relativepoint[3];
7217         float color[3];
7218         float dir[3];
7219         float dist;
7220         float dist2;
7221         float intensity;
7222         float sample[5*3];
7223         float lightradius2;
7224
7225         if (r_fullbright.integer)
7226         {
7227                 VectorSet(ambient, 1, 1, 1);
7228                 VectorClear(diffuse);
7229                 VectorClear(lightdir);
7230                 return;
7231         }
7232
7233         if (flags == LP_LIGHTMAP)
7234         {
7235                 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7236                 VectorClear(diffuse);
7237                 VectorClear(lightdir);
7238                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7239                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
7240                 else
7241                         VectorSet(ambient, 1, 1, 1);
7242                 return;
7243         }
7244
7245         memset(sample, 0, sizeof(sample));
7246         VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
7247
7248         if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
7249         {
7250                 vec3_t tempambient;
7251                 VectorClear(tempambient);
7252                 VectorClear(color);
7253                 VectorClear(relativepoint);
7254                 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
7255                 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
7256                 VectorScale(color, r_refdef.lightmapintensity, color);
7257                 VectorAdd(sample, tempambient, sample);
7258                 VectorMA(sample    , 0.5f            , color, sample    );
7259                 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7260                 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7261                 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7262                 // calculate a weighted average light direction as well
7263                 intensity = VectorLength(color);
7264                 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7265         }
7266
7267         if (flags & LP_RTWORLD)
7268         {
7269                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
7270                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
7271                 for (i = 0; i < numlights; i++)
7272                 {
7273                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
7274                         if (!dlight)
7275                                 continue;
7276                         light = &dlight->rtlight;
7277                         if (!(light->flags & flag))
7278                                 continue;
7279                         // sample
7280                         lightradius2 = light->radius * light->radius;
7281                         VectorSubtract(light->shadoworigin, p, relativepoint);
7282                         dist2 = VectorLength2(relativepoint);
7283                         if (dist2 >= lightradius2)
7284                                 continue;
7285                         dist = sqrt(dist2) / light->radius;
7286                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
7287                         if (intensity <= 0.0f)
7288                                 continue;
7289                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7290                                 continue;
7291                         // scale down intensity to add to both ambient and diffuse
7292                         //intensity *= 0.5f;
7293                         VectorNormalize(relativepoint);
7294                         VectorScale(light->currentcolor, intensity, color);
7295                         VectorMA(sample    , 0.5f            , color, sample    );
7296                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7297                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7298                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7299                         // calculate a weighted average light direction as well
7300                         intensity *= VectorLength(color);
7301                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7302                 }
7303                 // FIXME: sample bouncegrid too!
7304         }
7305
7306         if (flags & LP_DYNLIGHT)
7307         {
7308                 // sample dlights
7309                 for (i = 0;i < r_refdef.scene.numlights;i++)
7310                 {
7311                         light = r_refdef.scene.lights[i];
7312                         // sample
7313                         lightradius2 = light->radius * light->radius;
7314                         VectorSubtract(light->shadoworigin, p, relativepoint);
7315                         dist2 = VectorLength2(relativepoint);
7316                         if (dist2 >= lightradius2)
7317                                 continue;
7318                         dist = sqrt(dist2) / light->radius;
7319                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
7320                         if (intensity <= 0.0f)
7321                                 continue;
7322                         if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
7323                                 continue;
7324                         // scale down intensity to add to both ambient and diffuse
7325                         //intensity *= 0.5f;
7326                         VectorNormalize(relativepoint);
7327                         VectorScale(light->currentcolor, intensity, color);
7328                         VectorMA(sample    , 0.5f            , color, sample    );
7329                         VectorMA(sample + 3, relativepoint[0], color, sample + 3);
7330                         VectorMA(sample + 6, relativepoint[1], color, sample + 6);
7331                         VectorMA(sample + 9, relativepoint[2], color, sample + 9);
7332                         // calculate a weighted average light direction as well
7333                         intensity *= VectorLength(color);
7334                         VectorMA(sample + 12, intensity, relativepoint, sample + 12);
7335                 }
7336         }
7337
7338         // calculate the direction we'll use to reduce the sample to a directional light source
7339         VectorCopy(sample + 12, dir);
7340         //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
7341         VectorNormalize(dir);
7342         // extract the diffuse color along the chosen direction and scale it
7343         diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
7344         diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
7345         diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
7346         // subtract some of diffuse from ambient
7347         VectorMA(sample, -0.333f, diffuse, ambient);
7348         // store the normalized lightdir
7349         VectorCopy(dir, lightdir);
7350 }