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