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