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