]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Fix a few compile warnings. Remove unused locals.
[xonotic/darkplaces.git] / r_shadow.c
1 #include "quakedef.h"
2 #include "r_shadow.h"
3 #include "cl_collision.h"
4 #include "portals.h"
5 #include "image.h"
6
7 static void R_Shadow_EditLights_Init(void);
8
9 typedef enum r_shadow_rendermode_e
10 {
11         R_SHADOW_RENDERMODE_NONE,
12         R_SHADOW_RENDERMODE_ZPASS_STENCIL,
13         R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
14         R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
15         R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
16         R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
17         R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
18         R_SHADOW_RENDERMODE_LIGHT_GLSL,
19         R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
20         R_SHADOW_RENDERMODE_VISIBLELIGHTING,
21         R_SHADOW_RENDERMODE_SHADOWMAP2D
22 }
23 r_shadow_rendermode_t;
24
25 typedef enum r_shadow_shadowmode_e
26 {
27         R_SHADOW_SHADOWMODE_SHADOWMAP2D
28 }
29 r_shadow_shadowmode_t;
30
31 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
32 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
33 int r_shadow_scenemaxlights;
34 int r_shadow_scenenumlights;
35 rtlight_t **r_shadow_scenelightlist; // includes both static lights and dlights, as filtered by appropriate flags
36 qboolean r_shadow_usingshadowmap2d;
37 qboolean r_shadow_usingshadowmaportho;
38 int r_shadow_shadowmapside;
39 float r_shadow_lightshadowmap_texturescale[4]; // xy = scale, zw = offset
40 float r_shadow_lightshadowmap_parameters[4]; // x = frustum width in pixels (excludes border), y = z scale, z = size of viewport, w = z center
41 float r_shadow_modelshadowmap_texturescale[4]; // xy = scale, zw = offset
42 float r_shadow_modelshadowmap_parameters[4]; // xyz = scale, w = shadow brightness
43 #if 0
44 int r_shadow_drawbuffer;
45 int r_shadow_readbuffer;
46 #endif
47 int r_shadow_cullface_front, r_shadow_cullface_back;
48 GLuint r_shadow_fbo2d;
49 r_shadow_shadowmode_t r_shadow_shadowmode;
50 int r_shadow_shadowmapfilterquality;
51 int r_shadow_shadowmapdepthbits;
52 int r_shadow_shadowmapmaxsize;
53 int r_shadow_shadowmaptexturesize;
54 qboolean r_shadow_shadowmapvsdct;
55 qboolean r_shadow_shadowmapsampler;
56 qboolean r_shadow_shadowmapshadowsampler;
57 int r_shadow_shadowmappcf;
58 int r_shadow_shadowmapborder;
59 matrix4x4_t r_shadow_shadowmapmatrix;
60 int r_shadow_lightscissor[4];
61 qboolean r_shadow_usingdeferredprepass;
62 qboolean r_shadow_shadowmapdepthtexture;
63 mod_alloclightmap_state_t r_shadow_shadowmapatlas_state;
64 int r_shadow_shadowmapatlas_modelshadows_x;
65 int r_shadow_shadowmapatlas_modelshadows_y;
66 int r_shadow_shadowmapatlas_modelshadows_size;
67 int maxshadowtriangles;
68 int *shadowelements;
69
70 int maxshadowvertices;
71 float *shadowvertex3f;
72
73 int maxshadowmark;
74 int numshadowmark;
75 int *shadowmark;
76 int *shadowmarklist;
77 int shadowmarkcount;
78
79 int maxshadowsides;
80 int numshadowsides;
81 unsigned char *shadowsides;
82 int *shadowsideslist;
83
84 int maxvertexupdate;
85 int *vertexupdate;
86 int *vertexremap;
87 int vertexupdatenum;
88
89 int r_shadow_buffer_numleafpvsbytes;
90 unsigned char *r_shadow_buffer_visitingleafpvs;
91 unsigned char *r_shadow_buffer_leafpvs;
92 int *r_shadow_buffer_leaflist;
93
94 int r_shadow_buffer_numsurfacepvsbytes;
95 unsigned char *r_shadow_buffer_surfacepvs;
96 int *r_shadow_buffer_surfacelist;
97 unsigned char *r_shadow_buffer_surfacesides;
98
99 int r_shadow_buffer_numshadowtrispvsbytes;
100 unsigned char *r_shadow_buffer_shadowtrispvs;
101 int r_shadow_buffer_numlighttrispvsbytes;
102 unsigned char *r_shadow_buffer_lighttrispvs;
103
104 rtexturepool_t *r_shadow_texturepool;
105 rtexture_t *r_shadow_attenuationgradienttexture;
106 skinframe_t *r_shadow_lightcorona;
107 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
108 rtexture_t *r_shadow_shadowmap2ddepthtexture;
109 rtexture_t *r_shadow_shadowmapvsdcttexture;
110
111 GLuint r_shadow_prepassgeometryfbo;
112 GLuint r_shadow_prepasslightingdiffusespecularfbo;
113 GLuint r_shadow_prepasslightingdiffusefbo;
114 int r_shadow_prepass_width;
115 int r_shadow_prepass_height;
116 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
117 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
118 rtexture_t *r_shadow_prepasslightingdiffusetexture;
119 rtexture_t *r_shadow_prepasslightingspeculartexture;
120
121 int r_shadow_viewfbo;
122 rtexture_t *r_shadow_viewdepthtexture;
123 rtexture_t *r_shadow_viewcolortexture;
124 int r_shadow_viewx;
125 int r_shadow_viewy;
126 int r_shadow_viewwidth;
127 int r_shadow_viewheight;
128
129 // lights are reloaded when this changes
130 char r_shadow_mapname[MAX_QPATH];
131
132 // buffer for doing corona fading
133 unsigned int r_shadow_occlusion_buf = 0;
134
135 // used only for light filters (cubemaps)
136 rtexturepool_t *r_shadow_filters_texturepool;
137
138 cvar_t r_shadow_bumpscale_basetexture = {CVAR_CLIENT, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
139 cvar_t r_shadow_bumpscale_bumpmap = {CVAR_CLIENT, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
140 cvar_t r_shadow_debuglight = {CVAR_CLIENT, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
141 cvar_t r_shadow_deferred = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
142 cvar_t r_shadow_usebihculling = {CVAR_CLIENT, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
143 cvar_t r_shadow_usenormalmap = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
144 cvar_t r_shadow_gloss = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
145 cvar_t r_shadow_gloss2intensity = {CVAR_CLIENT, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
146 cvar_t r_shadow_glossintensity = {CVAR_CLIENT, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
147 cvar_t r_shadow_glossexponent = {CVAR_CLIENT, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
148 cvar_t r_shadow_gloss2exponent = {CVAR_CLIENT, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
149 cvar_t r_shadow_glossexact = {CVAR_CLIENT, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
150 cvar_t r_shadow_lightattenuationdividebias = {CVAR_CLIENT, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
151 cvar_t r_shadow_lightattenuationlinearscale = {CVAR_CLIENT, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
152 cvar_t r_shadow_lightintensityscale = {CVAR_CLIENT, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
153 cvar_t r_shadow_lightradiusscale = {CVAR_CLIENT, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
154 cvar_t r_shadow_projectdistance = {CVAR_CLIENT, "r_shadow_projectdistance", "0", "how far to cast shadows"};
155 cvar_t r_shadow_frontsidecasting = {CVAR_CLIENT, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
156 cvar_t r_shadow_realtime_dlight = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
157 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
158 cvar_t r_shadow_realtime_dlight_svbspculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
159 cvar_t r_shadow_realtime_dlight_portalculling = {CVAR_CLIENT, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
160 cvar_t r_shadow_realtime_world = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
161 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {CVAR_CLIENT, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
162 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
163 cvar_t r_shadow_realtime_world_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
164 cvar_t r_shadow_realtime_world_compile = {CVAR_CLIENT, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
165 cvar_t r_shadow_realtime_world_compileshadow = {CVAR_CLIENT, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
166 cvar_t r_shadow_realtime_world_compilesvbsp = {CVAR_CLIENT, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
167 cvar_t r_shadow_realtime_world_compileportalculling = {CVAR_CLIENT, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
168 cvar_t r_shadow_scissor = {CVAR_CLIENT, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
169 cvar_t r_shadow_shadowmapping = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (shadow rendering by depth texture sampling)"};
170 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
171 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
172 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
173 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
174 cvar_t r_shadow_shadowmapping_minsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "limit of shadowmap side size - must be at least r_shadow_shadowmapping_bordersize+2"};
175 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "limit of shadowmap side size - can not be more than 1/8th of atlassize because lights store 6 sides (2x3 grid) and sometimes 12 sides (4x3 grid for shadows from EF_NOSELFSHADOW entities) and there are multiple lights..."};
176 cvar_t r_shadow_shadowmapping_texturesize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_texturesize", "8192", "size of shadowmap atlas texture - all shadowmaps are packed into this texture at frame start"};
177 cvar_t r_shadow_shadowmapping_precision = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
178 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
179 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
180 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "5", "shadowmap size bias for filtering"};
181 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
182 cvar_t r_shadow_shadowmapping_bias = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
183 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
184 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
185 cvar_t r_shadow_sortsurfaces = {CVAR_CLIENT, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
186 cvar_t r_shadow_culllights_pvs = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_pvs", "1", "check if light overlaps any visible bsp leafs when determining if the light is visible"};
187 cvar_t r_shadow_culllights_trace = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace", "1", "use raytraces from the eye to random places within light bounds to determine if the light is visible"};
188 cvar_t r_shadow_culllights_trace_eyejitter = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_eyejitter", "16", "offset eye location randomly by this much"};
189 cvar_t r_shadow_culllights_trace_enlarge = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_enlarge", "0", "make light bounds bigger by *(1.0+enlarge)"};
190 cvar_t r_shadow_culllights_trace_expand = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_expand", "8", "make light bounds bigger by this many units"};
191 cvar_t r_shadow_culllights_trace_pad = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_pad", "8", "accept traces that hit within this many units of the light bounds"};
192 cvar_t r_shadow_culllights_trace_samples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_samples", "16", "use this many traces to random positions (in addition to center trace)"};
193 cvar_t r_shadow_culllights_trace_tempsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_tempsamples", "16", "use this many traces if the light was created by csqc (no inter-frame caching), -1 disables the check (to avoid flicker entirely)"};
194 cvar_t r_shadow_culllights_trace_delay = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_culllights_trace_delay", "1", "light will be considered visible for this many seconds after any trace connects"};
195 cvar_t r_shadow_bouncegrid = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
196 cvar_t r_shadow_bouncegrid_blur = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_blur", "0", "apply a 1-radius blur on bouncegrid to denoise it and deal with boundary issues with surfaces"};
197 cvar_t r_shadow_bouncegrid_dynamic_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_bounceminimumintensity", "0.05", "stop bouncing once intensity drops below this fraction of the original particle color"};
198 cvar_t r_shadow_bouncegrid_dynamic_culllightpaths = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_culllightpaths", "0", "skip accumulating light in the bouncegrid texture where the light paths are out of view (dynamic mode only)"};
199 cvar_t r_shadow_bouncegrid_dynamic_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_directionalshading", "1", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
200 cvar_t r_shadow_bouncegrid_dynamic_dlightparticlemultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_dlightparticlemultiplier", "1", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
201 cvar_t r_shadow_bouncegrid_dynamic_hitmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
202 cvar_t r_shadow_bouncegrid_dynamic_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1)"};
203 cvar_t r_shadow_bouncegrid_dynamic_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0)"};
204 cvar_t r_shadow_bouncegrid_dynamic_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_maxphotons", "25000", "upper bound on photons to shoot per update, divided proportionately between lights - normally the number of photons is calculated by energyperphoton"};
205 cvar_t r_shadow_bouncegrid_dynamic_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_quality", "1", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
206 cvar_t r_shadow_bouncegrid_dynamic_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_spacing", "64", "unit size of bouncegrid pixel"};
207 cvar_t r_shadow_bouncegrid_dynamic_updateinterval = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
208 cvar_t r_shadow_bouncegrid_dynamic_x = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_x", "64", "maximum texture size of bouncegrid on X axis"};
209 cvar_t r_shadow_bouncegrid_dynamic_y = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_y", "64", "maximum texture size of bouncegrid on Y axis"};
210 cvar_t r_shadow_bouncegrid_dynamic_z = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_dynamic_z", "32", "maximum texture size of bouncegrid on Z axis"};
211 cvar_t r_shadow_bouncegrid_floatcolors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_floatcolors", "1", "upload texture as RGBA16F (or RGBA32F when set to 2) rather than RGBA8 format - this gives more dynamic range and accuracy"};
212 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
213 cvar_t r_shadow_bouncegrid_intensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
214 cvar_t r_shadow_bouncegrid_lightpathsize = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_lightpathsize", "64", "radius (in game units) of the light path for accumulation of light in the bouncegrid texture"};
215 cvar_t r_shadow_bouncegrid_normalizevectors = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_normalizevectors", "1", "normalize random vectors (otherwise their length can vary, which dims the lighting further from the light)"};
216 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "4", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
217 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
218 cvar_t r_shadow_bouncegrid_rng_seed = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_seed", "0", "0+ = use this number as RNG seed, -1 = use time instead for disco-like craziness in dynamic mode"};
219 cvar_t r_shadow_bouncegrid_rng_type = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_rng_type", "0", "0 = Lehmer 128bit RNG (slow but high quality), 1 = lhcheeserand 32bit RNG (quick)"};
220 cvar_t r_shadow_bouncegrid_static = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
221 cvar_t r_shadow_bouncegrid_static_bounceminimumintensity = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_bounceminimumintensity", "0.01", "stop bouncing once intensity drops below this fraction of the original particle color"};
222 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
223 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "5", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
224 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
225 cvar_t r_shadow_bouncegrid_static_maxphotons = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_maxphotons", "250000", "upper bound on photons in static mode"};
226 cvar_t r_shadow_bouncegrid_static_quality = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_quality", "16", "amount of photons that should be fired (this is multiplied by spacing ^ 2 to make it adaptive with spacing changes)"};
227 cvar_t r_shadow_bouncegrid_static_spacing = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_static_spacing", "64", "unit size of bouncegrid pixel when in static mode"};
228 cvar_t r_shadow_bouncegrid_subsamples = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_subsamples", "1", "when generating the texture, sample this many points along each dimension (multisampling uses more compute but not more memory bandwidth)"};
229 cvar_t r_shadow_bouncegrid_threaded = {CVAR_CLIENT | CVAR_SAVE, "r_shadow_bouncegrid_threaded", "1", "enables use of taskqueue_maxthreads to perform the traces and slice rendering of bouncegrid"};
230 cvar_t r_coronas = {CVAR_CLIENT | CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
231 cvar_t r_coronas_occlusionsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
232 cvar_t r_coronas_occlusionquery = {CVAR_CLIENT | CVAR_SAVE, "r_coronas_occlusionquery", "0", "fades coronas according to visibility"};
233 cvar_t gl_flashblend = {CVAR_CLIENT | CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
234 cvar_t r_editlights = {CVAR_CLIENT, "r_editlights", "0", "enables .rtlights file editing mode"};
235 cvar_t r_editlights_cursordistance = {CVAR_CLIENT, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
236 cvar_t r_editlights_cursorpushback = {CVAR_CLIENT, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
237 cvar_t r_editlights_cursorpushoff = {CVAR_CLIENT, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
238 cvar_t r_editlights_cursorgrid = {CVAR_CLIENT, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
239 cvar_t r_editlights_quakelightsizescale = {CVAR_CLIENT | CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
240 cvar_t r_editlights_drawproperties = {CVAR_CLIENT, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
241 cvar_t r_editlights_current_origin = {CVAR_CLIENT, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
242 cvar_t r_editlights_current_angles = {CVAR_CLIENT, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
243 cvar_t r_editlights_current_color = {CVAR_CLIENT, "r_editlights_current_color", "1 1 1", "color of selected light"};
244 cvar_t r_editlights_current_radius = {CVAR_CLIENT, "r_editlights_current_radius", "0", "radius of selected light"};
245 cvar_t r_editlights_current_corona = {CVAR_CLIENT, "r_editlights_current_corona", "0", "corona intensity of selected light"};
246 cvar_t r_editlights_current_coronasize = {CVAR_CLIENT, "r_editlights_current_coronasize", "0", "corona size of selected light"};
247 cvar_t r_editlights_current_style = {CVAR_CLIENT, "r_editlights_current_style", "0", "style of selected light"};
248 cvar_t r_editlights_current_shadows = {CVAR_CLIENT, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
249 cvar_t r_editlights_current_cubemap = {CVAR_CLIENT, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
250 cvar_t r_editlights_current_ambient = {CVAR_CLIENT, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
251 cvar_t r_editlights_current_diffuse = {CVAR_CLIENT, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
252 cvar_t r_editlights_current_specular = {CVAR_CLIENT, "r_editlights_current_specular", "1", "specular intensity of selected light"};
253 cvar_t r_editlights_current_normalmode = {CVAR_CLIENT, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
254 cvar_t r_editlights_current_realtimemode = {CVAR_CLIENT, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
255
256 r_shadow_bouncegrid_state_t r_shadow_bouncegrid_state;
257
258 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
259 #define ATTENTABLESIZE 256
260 // 1D gradient, 2D circle and 3D sphere attenuation textures
261 #define ATTEN1DSIZE 32
262 #define ATTEN2DSIZE 64
263 #define ATTEN3DSIZE 32
264
265 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
266 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
267 static float r_shadow_attentable[ATTENTABLESIZE+1];
268
269 rtlight_t *r_shadow_compilingrtlight;
270 static memexpandablearray_t r_shadow_worldlightsarray;
271 dlight_t *r_shadow_selectedlight;
272 dlight_t r_shadow_bufferlight;
273 vec3_t r_editlights_cursorlocation;
274 qboolean r_editlights_lockcursor;
275
276 extern int con_vislines;
277
278 void R_Shadow_UncompileWorldLights(void);
279 void R_Shadow_ClearWorldLights(void);
280 void R_Shadow_SaveWorldLights(void);
281 void R_Shadow_LoadWorldLights(void);
282 void R_Shadow_LoadLightsFile(void);
283 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
284 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd);
285 static void R_Shadow_MakeTextures(void);
286
287 #define EDLIGHTSPRSIZE                  8
288 skinframe_t *r_editlights_sprcursor;
289 skinframe_t *r_editlights_sprlight;
290 skinframe_t *r_editlights_sprnoshadowlight;
291 skinframe_t *r_editlights_sprcubemaplight;
292 skinframe_t *r_editlights_sprcubemapnoshadowlight;
293 skinframe_t *r_editlights_sprselection;
294
295 static void R_Shadow_DrawModelShadowMaps(void);
296 static void R_Shadow_MakeShadowMap(int texturesize);
297 static void R_Shadow_MakeVSDCT(void);
298 static void R_Shadow_SetShadowMode(void)
299 {
300         r_shadow_shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
301         r_shadow_shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
302         r_shadow_shadowmapmaxsize = bound(r_shadow_shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, r_shadow_shadowmaptexturesize / 8);
303         r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32;
304         r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
305         r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
306         r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
307         r_shadow_shadowmapsampler = false;
308         r_shadow_shadowmappcf = 0;
309         r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
310         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
311         Mod_AllocLightmap_Init(&r_shadow_shadowmapatlas_state, r_main_mempool, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize);
312         if (r_shadow_shadowmapping.integer || r_shadow_deferred.integer)
313         {
314                 switch(vid.renderpath)
315                 {
316                 case RENDERPATH_GL32:
317                         if(r_shadow_shadowmapfilterquality < 0)
318                         {
319                                 if (!r_fb.usedepthtextures)
320                                         r_shadow_shadowmappcf = 1;
321                                 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && r_shadow_shadowmapshadowsampler)
322                                 {
323                                         r_shadow_shadowmapsampler = true;
324                                         r_shadow_shadowmappcf = 1;
325                                 }
326                                 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
327                                         r_shadow_shadowmappcf = 1;
328                                 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
329                                         r_shadow_shadowmappcf = 1;
330                                 else
331                                         r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
332                         }
333                         else
334                         {
335                 r_shadow_shadowmapsampler = r_shadow_shadowmapshadowsampler;
336                                 switch (r_shadow_shadowmapfilterquality)
337                                 {
338                                 case 1:
339                                         break;
340                                 case 2:
341                                         r_shadow_shadowmappcf = 1;
342                                         break;
343                                 case 3:
344                                         r_shadow_shadowmappcf = 1;
345                                         break;
346                                 case 4:
347                                         r_shadow_shadowmappcf = 2;
348                                         break;
349                                 }
350                         }
351                         if (!r_fb.usedepthtextures)
352                                 r_shadow_shadowmapsampler = false;
353                         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
354                         break;
355                 case RENDERPATH_GLES2:
356                         break;
357                 }
358         }
359
360         if(R_CompileShader_CheckStaticParms())
361                 R_GLSL_Restart_f(&cmd_client);
362 }
363
364 qboolean R_Shadow_ShadowMappingEnabled(void)
365 {
366         switch (r_shadow_shadowmode)
367         {
368         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
369                 return true;
370         default:
371                 return false;
372         }
373 }
374
375 static void R_Shadow_FreeShadowMaps(void)
376 {
377         Mod_AllocLightmap_Free(&r_shadow_shadowmapatlas_state);
378
379         R_Shadow_SetShadowMode();
380
381         R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
382
383         r_shadow_fbo2d = 0;
384
385         if (r_shadow_shadowmap2ddepthtexture)
386                 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
387         r_shadow_shadowmap2ddepthtexture = NULL;
388
389         if (r_shadow_shadowmap2ddepthbuffer)
390                 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
391         r_shadow_shadowmap2ddepthbuffer = NULL;
392
393         if (r_shadow_shadowmapvsdcttexture)
394                 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
395         r_shadow_shadowmapvsdcttexture = NULL;
396 }
397
398 static void r_shadow_start(void)
399 {
400         // allocate vertex processing arrays
401         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
402         r_shadow_attenuationgradienttexture = NULL;
403         r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
404         r_shadow_shadowmap2ddepthtexture = NULL;
405         r_shadow_shadowmap2ddepthbuffer = NULL;
406         r_shadow_shadowmapvsdcttexture = NULL;
407         r_shadow_shadowmapmaxsize = 0;
408         r_shadow_shadowmaptexturesize = 0;
409         r_shadow_shadowmapfilterquality = -1;
410         r_shadow_shadowmapdepthbits = 0;
411         r_shadow_shadowmapvsdct = false;
412         r_shadow_shadowmapsampler = false;
413         r_shadow_shadowmappcf = 0;
414         r_shadow_fbo2d = 0;
415
416         R_Shadow_FreeShadowMaps();
417
418         r_shadow_texturepool = NULL;
419         r_shadow_filters_texturepool = NULL;
420         R_Shadow_MakeTextures();
421         r_shadow_scenemaxlights = 0;
422         r_shadow_scenenumlights = 0;
423         r_shadow_scenelightlist = NULL;
424         maxshadowtriangles = 0;
425         shadowelements = NULL;
426         maxshadowvertices = 0;
427         shadowvertex3f = NULL;
428         maxvertexupdate = 0;
429         vertexupdate = NULL;
430         vertexremap = NULL;
431         vertexupdatenum = 0;
432         maxshadowmark = 0;
433         numshadowmark = 0;
434         shadowmark = NULL;
435         shadowmarklist = NULL;
436         shadowmarkcount = 0;
437         maxshadowsides = 0;
438         numshadowsides = 0;
439         shadowsides = NULL;
440         shadowsideslist = NULL;
441         r_shadow_buffer_numleafpvsbytes = 0;
442         r_shadow_buffer_visitingleafpvs = NULL;
443         r_shadow_buffer_leafpvs = NULL;
444         r_shadow_buffer_leaflist = NULL;
445         r_shadow_buffer_numsurfacepvsbytes = 0;
446         r_shadow_buffer_surfacepvs = NULL;
447         r_shadow_buffer_surfacelist = NULL;
448         r_shadow_buffer_surfacesides = NULL;
449         r_shadow_buffer_numshadowtrispvsbytes = 0;
450         r_shadow_buffer_shadowtrispvs = NULL;
451         r_shadow_buffer_numlighttrispvsbytes = 0;
452         r_shadow_buffer_lighttrispvs = NULL;
453
454         r_shadow_usingdeferredprepass = false;
455         r_shadow_prepass_width = r_shadow_prepass_height = 0;
456
457         // determine renderpath specific capabilities, we don't need to figure
458         // these out per frame...
459         switch(vid.renderpath)
460         {
461         case RENDERPATH_GL32:
462                 r_shadow_bouncegrid_state.allowdirectionalshading = true;
463                 r_shadow_bouncegrid_state.capable = true;
464                 break;
465         case RENDERPATH_GLES2:
466                 // for performance reasons, do not use directional shading on GLES devices
467                 r_shadow_bouncegrid_state.capable = true;
468                 break;
469         }
470 }
471
472 static void R_Shadow_FreeDeferred(void);
473 static void r_shadow_shutdown(void)
474 {
475         CHECKGLERROR
476         R_Shadow_UncompileWorldLights();
477
478         R_Shadow_FreeShadowMaps();
479
480         r_shadow_usingdeferredprepass = false;
481         if (r_shadow_prepass_width)
482                 R_Shadow_FreeDeferred();
483         r_shadow_prepass_width = r_shadow_prepass_height = 0;
484
485         CHECKGLERROR
486         r_shadow_scenemaxlights = 0;
487         r_shadow_scenenumlights = 0;
488         if (r_shadow_scenelightlist)
489                 Mem_Free(r_shadow_scenelightlist);
490         r_shadow_scenelightlist = NULL;
491         r_shadow_bouncegrid_state.highpixels = NULL;
492         if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
493         if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
494         if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
495         if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
496         if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
497         if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
498         if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
499         memset(&r_shadow_bouncegrid_state, 0, sizeof(r_shadow_bouncegrid_state));
500         r_shadow_attenuationgradienttexture = NULL;
501         R_FreeTexturePool(&r_shadow_texturepool);
502         R_FreeTexturePool(&r_shadow_filters_texturepool);
503         maxshadowtriangles = 0;
504         if (shadowelements)
505                 Mem_Free(shadowelements);
506         shadowelements = NULL;
507         if (shadowvertex3f)
508                 Mem_Free(shadowvertex3f);
509         shadowvertex3f = NULL;
510         maxvertexupdate = 0;
511         if (vertexupdate)
512                 Mem_Free(vertexupdate);
513         vertexupdate = NULL;
514         if (vertexremap)
515                 Mem_Free(vertexremap);
516         vertexremap = NULL;
517         vertexupdatenum = 0;
518         maxshadowmark = 0;
519         numshadowmark = 0;
520         if (shadowmark)
521                 Mem_Free(shadowmark);
522         shadowmark = NULL;
523         if (shadowmarklist)
524                 Mem_Free(shadowmarklist);
525         shadowmarklist = NULL;
526         shadowmarkcount = 0;
527         maxshadowsides = 0;
528         numshadowsides = 0;
529         if (shadowsides)
530                 Mem_Free(shadowsides);
531         shadowsides = NULL;
532         if (shadowsideslist)
533                 Mem_Free(shadowsideslist);
534         shadowsideslist = NULL;
535         r_shadow_buffer_numleafpvsbytes = 0;
536         if (r_shadow_buffer_visitingleafpvs)
537                 Mem_Free(r_shadow_buffer_visitingleafpvs);
538         r_shadow_buffer_visitingleafpvs = NULL;
539         if (r_shadow_buffer_leafpvs)
540                 Mem_Free(r_shadow_buffer_leafpvs);
541         r_shadow_buffer_leafpvs = NULL;
542         if (r_shadow_buffer_leaflist)
543                 Mem_Free(r_shadow_buffer_leaflist);
544         r_shadow_buffer_leaflist = NULL;
545         r_shadow_buffer_numsurfacepvsbytes = 0;
546         if (r_shadow_buffer_surfacepvs)
547                 Mem_Free(r_shadow_buffer_surfacepvs);
548         r_shadow_buffer_surfacepvs = NULL;
549         if (r_shadow_buffer_surfacelist)
550                 Mem_Free(r_shadow_buffer_surfacelist);
551         r_shadow_buffer_surfacelist = NULL;
552         if (r_shadow_buffer_surfacesides)
553                 Mem_Free(r_shadow_buffer_surfacesides);
554         r_shadow_buffer_surfacesides = NULL;
555         r_shadow_buffer_numshadowtrispvsbytes = 0;
556         if (r_shadow_buffer_shadowtrispvs)
557                 Mem_Free(r_shadow_buffer_shadowtrispvs);
558         r_shadow_buffer_numlighttrispvsbytes = 0;
559         if (r_shadow_buffer_lighttrispvs)
560                 Mem_Free(r_shadow_buffer_lighttrispvs);
561 }
562
563 static void r_shadow_newmap(void)
564 {
565         r_shadow_bouncegrid_state.highpixels = NULL;
566         if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
567         if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
568         if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
569         if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
570         if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
571         if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
572         if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
573
574         if (r_shadow_bouncegrid_state.texture)    { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
575         if (r_shadow_lightcorona)                 { R_SkinFrame_MarkUsed(r_shadow_lightcorona); }
576         if (r_editlights_sprcursor)               { R_SkinFrame_MarkUsed(r_editlights_sprcursor); }
577         if (r_editlights_sprlight)                { R_SkinFrame_MarkUsed(r_editlights_sprlight); }
578         if (r_editlights_sprnoshadowlight)        { R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight); }
579         if (r_editlights_sprcubemaplight)         { R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight); }
580         if (r_editlights_sprcubemapnoshadowlight) { R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight); }
581         if (r_editlights_sprselection)            { R_SkinFrame_MarkUsed(r_editlights_sprselection); }
582         if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
583                 R_Shadow_EditLights_Reload_f(&cmd_client);
584 }
585
586 void R_Shadow_Init(void)
587 {
588         Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
589         Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
590         Cvar_RegisterVariable(&r_shadow_usebihculling);
591         Cvar_RegisterVariable(&r_shadow_usenormalmap);
592         Cvar_RegisterVariable(&r_shadow_debuglight);
593         Cvar_RegisterVariable(&r_shadow_deferred);
594         Cvar_RegisterVariable(&r_shadow_gloss);
595         Cvar_RegisterVariable(&r_shadow_gloss2intensity);
596         Cvar_RegisterVariable(&r_shadow_glossintensity);
597         Cvar_RegisterVariable(&r_shadow_glossexponent);
598         Cvar_RegisterVariable(&r_shadow_gloss2exponent);
599         Cvar_RegisterVariable(&r_shadow_glossexact);
600         Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
601         Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
602         Cvar_RegisterVariable(&r_shadow_lightintensityscale);
603         Cvar_RegisterVariable(&r_shadow_lightradiusscale);
604         Cvar_RegisterVariable(&r_shadow_projectdistance);
605         Cvar_RegisterVariable(&r_shadow_frontsidecasting);
606         Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
607         Cvar_RegisterVariable(&r_shadow_realtime_dlight);
608         Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
609         Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
610         Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
611         Cvar_RegisterVariable(&r_shadow_realtime_world);
612         Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
613         Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
614         Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
615         Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
616         Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
617         Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
618         Cvar_RegisterVariable(&r_shadow_scissor);
619         Cvar_RegisterVariable(&r_shadow_shadowmapping);
620         Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
621         Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
622         Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
623         Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
624         Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
625         Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
626         Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
627         Cvar_RegisterVariable(&r_shadow_shadowmapping_texturesize);
628 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
629 //      Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
630         Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
631         Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
632         Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
633         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
634         Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
635         Cvar_RegisterVariable(&r_shadow_sortsurfaces);
636         Cvar_RegisterVariable(&r_shadow_culllights_pvs);
637         Cvar_RegisterVariable(&r_shadow_culllights_trace);
638         Cvar_RegisterVariable(&r_shadow_culllights_trace_eyejitter);
639         Cvar_RegisterVariable(&r_shadow_culllights_trace_enlarge);
640         Cvar_RegisterVariable(&r_shadow_culllights_trace_expand);
641         Cvar_RegisterVariable(&r_shadow_culllights_trace_pad);
642         Cvar_RegisterVariable(&r_shadow_culllights_trace_samples);
643         Cvar_RegisterVariable(&r_shadow_culllights_trace_tempsamples);
644         Cvar_RegisterVariable(&r_shadow_culllights_trace_delay);
645         Cvar_RegisterVariable(&r_shadow_bouncegrid);
646         Cvar_RegisterVariable(&r_shadow_bouncegrid_blur);
647         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_bounceminimumintensity);
648         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_culllightpaths);
649         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_directionalshading);
650         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_dlightparticlemultiplier);
651         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_hitmodels);
652         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_lightradiusscale);
653         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxbounce);
654         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_maxphotons);
655         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_quality);
656         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_spacing);
657         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_updateinterval);
658         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_x);
659         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_y);
660         Cvar_RegisterVariable(&r_shadow_bouncegrid_dynamic_z);
661         Cvar_RegisterVariable(&r_shadow_bouncegrid_floatcolors);
662         Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
663         Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
664         Cvar_RegisterVariable(&r_shadow_bouncegrid_lightpathsize);
665         Cvar_RegisterVariable(&r_shadow_bouncegrid_normalizevectors);
666         Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
667         Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
668         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_seed);
669         Cvar_RegisterVariable(&r_shadow_bouncegrid_rng_type);
670         Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
671         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_bounceminimumintensity);
672         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
673         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
674         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
675         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxphotons);
676         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_quality);
677         Cvar_RegisterVariable(&r_shadow_bouncegrid_static_spacing);
678         Cvar_RegisterVariable(&r_shadow_bouncegrid_subsamples);
679         Cvar_RegisterVariable(&r_shadow_bouncegrid_threaded);
680         Cvar_RegisterVariable(&r_coronas);
681         Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
682         Cvar_RegisterVariable(&r_coronas_occlusionquery);
683         Cvar_RegisterVariable(&gl_flashblend);
684         R_Shadow_EditLights_Init();
685         Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
686         r_shadow_scenemaxlights = 0;
687         r_shadow_scenenumlights = 0;
688         r_shadow_scenelightlist = NULL;
689         maxshadowtriangles = 0;
690         shadowelements = NULL;
691         maxshadowvertices = 0;
692         shadowvertex3f = NULL;
693         maxvertexupdate = 0;
694         vertexupdate = NULL;
695         vertexremap = NULL;
696         vertexupdatenum = 0;
697         maxshadowmark = 0;
698         numshadowmark = 0;
699         shadowmark = NULL;
700         shadowmarklist = NULL;
701         shadowmarkcount = 0;
702         maxshadowsides = 0;
703         numshadowsides = 0;
704         shadowsides = NULL;
705         shadowsideslist = NULL;
706         r_shadow_buffer_numleafpvsbytes = 0;
707         r_shadow_buffer_visitingleafpvs = NULL;
708         r_shadow_buffer_leafpvs = NULL;
709         r_shadow_buffer_leaflist = NULL;
710         r_shadow_buffer_numsurfacepvsbytes = 0;
711         r_shadow_buffer_surfacepvs = NULL;
712         r_shadow_buffer_surfacelist = NULL;
713         r_shadow_buffer_surfacesides = NULL;
714         r_shadow_buffer_shadowtrispvs = NULL;
715         r_shadow_buffer_lighttrispvs = NULL;
716         R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
717 }
718
719 matrix4x4_t matrix_attenuationxyz =
720 {
721         {
722                 {0.5, 0.0, 0.0, 0.5},
723                 {0.0, 0.5, 0.0, 0.5},
724                 {0.0, 0.0, 0.5, 0.5},
725                 {0.0, 0.0, 0.0, 1.0}
726         }
727 };
728
729 matrix4x4_t matrix_attenuationz =
730 {
731         {
732                 {0.0, 0.0, 0.5, 0.5},
733                 {0.0, 0.0, 0.0, 0.5},
734                 {0.0, 0.0, 0.0, 0.5},
735                 {0.0, 0.0, 0.0, 1.0}
736         }
737 };
738
739 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
740 {
741         numvertices = ((numvertices + 255) & ~255) * vertscale;
742         numtriangles = ((numtriangles + 255) & ~255) * triscale;
743         // make sure shadowelements is big enough for this volume
744         if (maxshadowtriangles < numtriangles)
745         {
746                 maxshadowtriangles = numtriangles;
747                 if (shadowelements)
748                         Mem_Free(shadowelements);
749                 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
750         }
751         // make sure shadowvertex3f is big enough for this volume
752         if (maxshadowvertices < numvertices)
753         {
754                 maxshadowvertices = numvertices;
755                 if (shadowvertex3f)
756                         Mem_Free(shadowvertex3f);
757                 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
758         }
759 }
760
761 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
762 {
763         int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
764         int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
765         int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
766         int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
767         if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
768         {
769                 if (r_shadow_buffer_visitingleafpvs)
770                         Mem_Free(r_shadow_buffer_visitingleafpvs);
771                 if (r_shadow_buffer_leafpvs)
772                         Mem_Free(r_shadow_buffer_leafpvs);
773                 if (r_shadow_buffer_leaflist)
774                         Mem_Free(r_shadow_buffer_leaflist);
775                 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
776                 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777                 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778                 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
779         }
780         if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
781         {
782                 if (r_shadow_buffer_surfacepvs)
783                         Mem_Free(r_shadow_buffer_surfacepvs);
784                 if (r_shadow_buffer_surfacelist)
785                         Mem_Free(r_shadow_buffer_surfacelist);
786                 if (r_shadow_buffer_surfacesides)
787                         Mem_Free(r_shadow_buffer_surfacesides);
788                 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
789                 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
790                 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791                 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
792         }
793         if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
794         {
795                 if (r_shadow_buffer_shadowtrispvs)
796                         Mem_Free(r_shadow_buffer_shadowtrispvs);
797                 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
798                 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
799         }
800         if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
801         {
802                 if (r_shadow_buffer_lighttrispvs)
803                         Mem_Free(r_shadow_buffer_lighttrispvs);
804                 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
805                 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
806         }
807 }
808
809 void R_Shadow_PrepareShadowMark(int numtris)
810 {
811         // make sure shadowmark is big enough for this volume
812         if (maxshadowmark < numtris)
813         {
814                 maxshadowmark = numtris;
815                 if (shadowmark)
816                         Mem_Free(shadowmark);
817                 if (shadowmarklist)
818                         Mem_Free(shadowmarklist);
819                 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
820                 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
821                 shadowmarkcount = 0;
822         }
823         shadowmarkcount++;
824         // if shadowmarkcount wrapped we clear the array and adjust accordingly
825         if (shadowmarkcount == 0)
826         {
827                 shadowmarkcount = 1;
828                 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
829         }
830         numshadowmark = 0;
831 }
832
833 void R_Shadow_PrepareShadowSides(int numtris)
834 {
835         if (maxshadowsides < numtris)
836         {
837                 maxshadowsides = numtris;
838                 if (shadowsides)
839                         Mem_Free(shadowsides);
840                 if (shadowsideslist)
841                         Mem_Free(shadowsideslist);
842                 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
843                 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
844         }
845         numshadowsides = 0;
846 }
847
848 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
849 {
850         // p1, p2, p3 are in the cubemap's local coordinate system
851         // bias = border/(size - border)
852         int mask = 0x3F;
853
854         float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
855                   dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
856                   dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
857         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
858                 mask &= (3<<4)
859                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
860                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
861                         | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
862         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
863                 mask &= (3<<4)
864                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
865                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))                    
866                         | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
867
868         dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
869         dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
870         dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
871         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
872                 mask &= (3<<0)
873                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
874                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))                    
875                         | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
876         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
877                 mask &= (3<<0)
878                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
879                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
880                         | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
881
882         dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
883         dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
884         dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
885         if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
886                 mask &= (3<<2)
887                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
888                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
889                         | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
890         if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
891                 mask &= (3<<2)
892                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
893                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
894                         | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
895
896         return mask;
897 }
898
899 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
900 {
901         vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
902         float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
903         int mask = 0x3F;
904
905         VectorSubtract(maxs, mins, radius);
906         VectorScale(radius, 0.5f, radius);
907         VectorAdd(mins, radius, center);
908         Matrix4x4_Transform(worldtolight, center, lightcenter);
909         Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
910         VectorSubtract(lightcenter, lightradius, pmin);
911         VectorAdd(lightcenter, lightradius, pmax);
912
913         dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
914         dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
915         if(ap1 > bias*an1 && ap2 > bias*an2)
916                 mask &= (3<<4)
917                         | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
918                         | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
919         if(an1 > bias*ap1 && an2 > bias*ap2)
920                 mask &= (3<<4)
921                         | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
922                         | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
923
924         dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
925         dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
926         if(ap1 > bias*an1 && ap2 > bias*an2)
927                 mask &= (3<<0)
928                         | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
929                         | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
930         if(an1 > bias*ap1 && an2 > bias*ap2)
931                 mask &= (3<<0)
932                         | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
933                         | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
934
935         dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
936         dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
937         if(ap1 > bias*an1 && ap2 > bias*an2)
938                 mask &= (3<<2)
939                         | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
940                         | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
941         if(an1 > bias*ap1 && an2 > bias*ap2)
942                 mask &= (3<<2)
943                         | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
944                         | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
945
946         return mask;
947 }
948
949 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
950
951 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
952 {
953         // p is in the cubemap's local coordinate system
954         // bias = border/(size - border)
955         float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
956         float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
957         float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
958         int mask = 0x3F;
959         if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
960         if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
961         if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
962         if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
963         if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
964         if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
965         return mask;
966 }
967
968 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
969 {
970         int i;
971         vec3_t o, p, n;
972         int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
973         float scale = (size - 2*border)/size, len;
974         float bias = border / (float)(size - border), dp, dn, ap, an;
975         // check if cone enclosing side would cross frustum plane
976         scale = 2 / (scale*scale + 2);
977         Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
978         for (i = 0;i < 5;i++)
979         {
980                 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
981                         continue;
982                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
983                 len = scale*VectorLength2(n);
984                 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
985                 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
986                 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
987         }
988         if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
989         {
990                 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
991                 len = scale*VectorLength2(n);
992                 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
993                 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
994                 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
995         }
996         // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
997         // check if frustum corners/origin cross plane sides
998 #if 1
999         // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1000         Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1001         dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1002         masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1003         masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1004         dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1005         masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1006         masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1007         dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1008         masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1009         masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1010         for (i = 0;i < 4;i++)
1011         {
1012                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1013                 VectorSubtract(n, p, n);
1014                 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1015                 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1016                 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1017                 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1018                 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1019                 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1020                 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1021                 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1022                 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1023         }
1024 #else
1025         // finite version, assumes corners are a finite distance from origin dependent on far plane
1026         for (i = 0;i < 5;i++)
1027         {
1028                 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1029                 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1030                 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1031                 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1032                 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1033                 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1034                 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1035                 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1036                 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1037                 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1038         }
1039 #endif
1040         return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1041 }
1042
1043 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)
1044 {
1045         int t, tend;
1046         const int *e;
1047         const float *v[3];
1048         float normal[3];
1049         vec3_t p[3];
1050         float bias;
1051         int mask, surfacemask = 0;
1052         if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1053                 return 0;
1054         bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1055         tend = firsttriangle + numtris;
1056         if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1057         {
1058                 // surface box entirely inside light box, no box cull
1059                 if (projectdirection)
1060                 {
1061                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1062                         {
1063                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1064                                 TriangleNormal(v[0], v[1], v[2], normal);
1065                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1066                                 {
1067                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1068                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1069                                         surfacemask |= mask;
1070                                         if(totals)
1071                                         {
1072                                                 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;
1073                                                 shadowsides[numshadowsides] = mask;
1074                                                 shadowsideslist[numshadowsides++] = t;
1075                                         }
1076                                 }
1077                         }
1078                 }
1079                 else
1080                 {
1081                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1082                         {
1083                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1084                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1085                                 {
1086                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1087                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1088                                         surfacemask |= mask;
1089                                         if(totals)
1090                                         {
1091                                                 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;
1092                                                 shadowsides[numshadowsides] = mask;
1093                                                 shadowsideslist[numshadowsides++] = t;
1094                                         }
1095                                 }
1096                         }
1097                 }
1098         }
1099         else
1100         {
1101                 // surface box not entirely inside light box, cull each triangle
1102                 if (projectdirection)
1103                 {
1104                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1105                         {
1106                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3,     v[2] = invertex3f + e[2] * 3;
1107                                 TriangleNormal(v[0], v[1], v[2], normal);
1108                                 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1109                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1110                                 {
1111                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1112                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1113                                         surfacemask |= mask;
1114                                         if(totals)
1115                                         {
1116                                                 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;
1117                                                 shadowsides[numshadowsides] = mask;
1118                                                 shadowsideslist[numshadowsides++] = t;
1119                                         }
1120                                 }
1121                         }
1122                 }
1123                 else
1124                 {
1125                         for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1126                         {
1127                                 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1128                                 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1129                                  && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1130                                 {
1131                                         Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1132                                         mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1133                                         surfacemask |= mask;
1134                                         if(totals)
1135                                         {
1136                                                 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;
1137                                                 shadowsides[numshadowsides] = mask;
1138                                                 shadowsideslist[numshadowsides++] = t;
1139                                         }
1140                                 }
1141                         }
1142                 }
1143         }
1144         return surfacemask;
1145 }
1146
1147 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)
1148 {
1149         int i, j, outtriangles = 0;
1150         int *outelement3i[6];
1151         if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1152                 return;
1153         outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1154         // make sure shadowelements is big enough for this mesh
1155         if (maxshadowtriangles < outtriangles)
1156                 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1157
1158         // compute the offset and size of the separate index lists for each cubemap side
1159         outtriangles = 0;
1160         for (i = 0;i < 6;i++)
1161         {
1162                 outelement3i[i] = shadowelements + outtriangles * 3;
1163                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1164                 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1165                 outtriangles += sidetotals[i];
1166         }
1167
1168         // gather up the (sparse) triangles into separate index lists for each cubemap side
1169         for (i = 0;i < numsidetris;i++)
1170         {
1171                 const int *element = elements + sidetris[i] * 3;
1172                 for (j = 0;j < 6;j++)
1173                 {
1174                         if (sides[i] & (1 << j))
1175                         {
1176                                 outelement3i[j][0] = element[0];
1177                                 outelement3i[j][1] = element[1];
1178                                 outelement3i[j][2] = element[2];
1179                                 outelement3i[j] += 3;
1180                         }
1181                 }
1182         }
1183
1184         Mod_ShadowMesh_AddMesh(r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, vertex3f, outtriangles, shadowelements);
1185 }
1186
1187 static void R_Shadow_MakeTextures_MakeCorona(void)
1188 {
1189         float dx, dy;
1190         int x, y, a;
1191         unsigned char pixels[32][32][4];
1192         for (y = 0;y < 32;y++)
1193         {
1194                 dy = (y - 15.5f) * (1.0f / 16.0f);
1195                 for (x = 0;x < 32;x++)
1196                 {
1197                         dx = (x - 15.5f) * (1.0f / 16.0f);
1198                         a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1199                         a = bound(0, a, 255);
1200                         pixels[y][x][0] = a;
1201                         pixels[y][x][1] = a;
1202                         pixels[y][x][2] = a;
1203                         pixels[y][x][3] = 255;
1204                 }
1205         }
1206         r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, 0, 0, 0, false);
1207 }
1208
1209 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1210 {
1211         float dist = sqrt(x*x+y*y+z*z);
1212         float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1213         // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1214         return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1215 }
1216
1217 static void R_Shadow_MakeTextures(void)
1218 {
1219         int x;
1220         float intensity, dist;
1221         unsigned int *data;
1222         R_Shadow_FreeShadowMaps();
1223         R_FreeTexturePool(&r_shadow_texturepool);
1224         r_shadow_texturepool = R_AllocTexturePool();
1225         r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1226         r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1227         data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1228         // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1229         for (x = 0;x <= ATTENTABLESIZE;x++)
1230         {
1231                 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1232                 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1233                 r_shadow_attentable[x] = bound(0, intensity, 1);
1234         }
1235         // 1D gradient texture
1236         for (x = 0;x < ATTEN1DSIZE;x++)
1237                 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1238         r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1239         Mem_Free(data);
1240
1241         R_Shadow_MakeTextures_MakeCorona();
1242
1243         // Editor light sprites
1244         r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1245         "................"
1246         ".3............3."
1247         "..5...2332...5.."
1248         "...7.3....3.7..."
1249         "....7......7...."
1250         "...3.7....7.3..."
1251         "..2...7..7...2.."
1252         "..3..........3.."
1253         "..3..........3.."
1254         "..2...7..7...2.."
1255         "...3.7....7.3..."
1256         "....7......7...."
1257         "...7.3....3.7..."
1258         "..5...2332...5.."
1259         ".3............3."
1260         "................"
1261         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1262         r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1263         "................"
1264         "................"
1265         "......1111......"
1266         "....11233211...."
1267         "...1234554321..."
1268         "...1356776531..."
1269         "..124677776421.."
1270         "..135777777531.."
1271         "..135777777531.."
1272         "..124677776421.."
1273         "...1356776531..."
1274         "...1234554321..."
1275         "....11233211...."
1276         "......1111......"
1277         "................"
1278         "................"
1279         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1280         r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1281         "................"
1282         "................"
1283         "......1111......"
1284         "....11233211...."
1285         "...1234554321..."
1286         "...1356226531..."
1287         "..12462..26421.."
1288         "..1352....2531.."
1289         "..1352....2531.."
1290         "..12462..26421.."
1291         "...1356226531..."
1292         "...1234554321..."
1293         "....11233211...."
1294         "......1111......"
1295         "................"
1296         "................"
1297         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1298         r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1299         "................"
1300         "................"
1301         "......2772......"
1302         "....27755772...."
1303         "..277533335772.."
1304         "..753333333357.."
1305         "..777533335777.."
1306         "..735775577537.."
1307         "..733357753337.."
1308         "..733337733337.."
1309         "..753337733357.."
1310         "..277537735772.."
1311         "....27777772...."
1312         "......2772......"
1313         "................"
1314         "................"
1315         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1316         r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1317         "................"
1318         "................"
1319         "......2772......"
1320         "....27722772...."
1321         "..2772....2772.."
1322         "..72........27.."
1323         "..7772....2777.."
1324         "..7.27722772.7.."
1325         "..7...2772...7.."
1326         "..7....77....7.."
1327         "..72...77...27.."
1328         "..2772.77.2772.."
1329         "....27777772...."
1330         "......2772......"
1331         "................"
1332         "................"
1333         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1334         r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1335         "................"
1336         ".777752..257777."
1337         ".742........247."
1338         ".72..........27."
1339         ".7............7."
1340         ".5............5."
1341         ".2............2."
1342         "................"
1343         "................"
1344         ".2............2."
1345         ".5............5."
1346         ".7............7."
1347         ".72..........27."
1348         ".742........247."
1349         ".777752..257777."
1350         "................"
1351         , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1352 }
1353
1354 void R_Shadow_RenderMode_Begin(void)
1355 {
1356 #if 0
1357         GLint drawbuffer;
1358         GLint readbuffer;
1359 #endif
1360
1361         if (r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1362          || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1363                 R_Shadow_MakeTextures();
1364
1365         CHECKGLERROR
1366         R_Mesh_ResetTextureState();
1367         GL_BlendFunc(GL_ONE, GL_ZERO);
1368         GL_DepthRange(0, 1);
1369         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1370         GL_DepthTest(true);
1371         GL_DepthMask(false);
1372         GL_Color(0, 0, 0, 1);
1373         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1374         
1375         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1376         r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1377
1378         CHECKGLERROR
1379 #if 0
1380         qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1381         qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1382         r_shadow_drawbuffer = drawbuffer;
1383         r_shadow_readbuffer = readbuffer;
1384 #endif
1385         r_shadow_cullface_front = r_refdef.view.cullface_front;
1386         r_shadow_cullface_back = r_refdef.view.cullface_back;
1387 }
1388
1389 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1390 {
1391         rsurface.rtlight = rtlight;
1392 }
1393
1394 void R_Shadow_RenderMode_Reset(void)
1395 {
1396         R_Mesh_ResetTextureState();
1397         R_Mesh_SetRenderTargets(r_shadow_viewfbo, r_shadow_viewdepthtexture, r_shadow_viewcolortexture, NULL, NULL, NULL);
1398         R_SetViewport(&r_refdef.view.viewport);
1399         GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1400         GL_DepthRange(0, 1);
1401         GL_DepthTest(true);
1402         GL_DepthMask(false);
1403         GL_DepthFunc(GL_LEQUAL);
1404         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1405         r_refdef.view.cullface_front = r_shadow_cullface_front;
1406         r_refdef.view.cullface_back = r_shadow_cullface_back;
1407         GL_CullFace(r_refdef.view.cullface_back);
1408         GL_Color(1, 1, 1, 1);
1409         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1410         GL_BlendFunc(GL_ONE, GL_ZERO);
1411         R_SetupShader_Generic_NoTexture(false, false);
1412         r_shadow_usingshadowmap2d = false;
1413 }
1414
1415 void R_Shadow_ClearStencil(void)
1416 {
1417         GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 0);
1418         r_refdef.stats[r_stat_lights_clears]++;
1419 }
1420
1421 static void R_Shadow_MakeVSDCT(void)
1422 {
1423         // maps to a 2x3 texture rectangle with normalized coordinates
1424         // +-
1425         // XX
1426         // YY
1427         // ZZ
1428         // stores abs(dir.xy), offset.xy/2.5
1429         unsigned char data[4*6] =
1430         {
1431                 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1432                 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1433                 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1434                 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1435                 0,   0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1436                 0,   0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1437         };
1438         r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1439 }
1440
1441 static void R_Shadow_MakeShadowMap(int texturesize)
1442 {
1443         switch (r_shadow_shadowmode)
1444         {
1445         case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
1446                 if (r_shadow_shadowmap2ddepthtexture) return;
1447                 if (r_fb.usedepthtextures)
1448                 {
1449                         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);
1450                         r_shadow_shadowmap2ddepthbuffer = NULL;
1451                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1452                 }
1453                 else
1454                 {
1455                         r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", texturesize, texturesize, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
1456                         r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", texturesize, texturesize, r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
1457                         r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1458                 }
1459                 break;
1460         default:
1461                 return;
1462         }
1463 }
1464
1465 void R_Shadow_ClearShadowMapTexture(void)
1466 {
1467         r_viewport_t viewport;
1468         float clearcolor[4];
1469
1470         // if they don't exist, create our textures now
1471         if (!r_shadow_shadowmap2ddepthtexture)
1472                 R_Shadow_MakeShadowMap(r_shadow_shadowmaptexturesize);
1473         if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1474                 R_Shadow_MakeVSDCT();
1475
1476         // we're setting up to render shadowmaps, so change rendermode
1477         r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1478
1479         R_Mesh_ResetTextureState();
1480         R_Shadow_RenderMode_Reset();
1481         if (r_shadow_shadowmap2ddepthbuffer)
1482                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1483         else
1484                 R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1485         R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1486         GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1487         GL_DepthMask(true);
1488         GL_DepthTest(true);
1489
1490         // we have to set a viewport to clear anything in some renderpaths (D3D)
1491         R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, r_shadow_shadowmaptexturesize, r_shadow_shadowmaptexturesize, 0, 0, 1.0, 1.0, 0.001f, 1.0f, NULL);
1492         R_SetViewport(&viewport);
1493         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1494         if (r_shadow_shadowmap2ddepthbuffer)
1495                 GL_ColorMask(1, 1, 1, 1);
1496         else
1497                 GL_ColorMask(0, 0, 0, 0);
1498         switch (vid.renderpath)
1499         {
1500         case RENDERPATH_GL32:
1501         case RENDERPATH_GLES2:
1502                 GL_CullFace(r_refdef.view.cullface_back);
1503                 break;
1504         }
1505         Vector4Set(clearcolor, 1, 1, 1, 1);
1506         if (r_shadow_shadowmap2ddepthbuffer)
1507                 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
1508         else
1509                 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
1510 }
1511
1512 static void R_Shadow_SetShadowmapParametersForLight(qboolean noselfshadowpass)
1513 {
1514         int size = rsurface.rtlight->shadowmapatlassidesize;
1515         float nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1516         float farclip = 1.0f;
1517         float bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1518         r_shadow_lightshadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
1519         r_shadow_lightshadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
1520         r_shadow_lightshadowmap_texturescale[2] = rsurface.rtlight->shadowmapatlasposition[0] + (noselfshadowpass ? size * 2 : 0);
1521         r_shadow_lightshadowmap_texturescale[3] = rsurface.rtlight->shadowmapatlasposition[1];
1522         r_shadow_lightshadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1523         r_shadow_lightshadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1524         r_shadow_lightshadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1525         r_shadow_lightshadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1526         if (r_shadow_shadowmap2ddepthbuffer)
1527         {
1528                 // completely different meaning than in depthtexture approach
1529                 r_shadow_lightshadowmap_parameters[1] = 0;
1530                 r_shadow_lightshadowmap_parameters[3] = -bias;
1531         }
1532 }
1533
1534 static void R_Shadow_RenderMode_ShadowMap(int side, int size, int x, int y)
1535 {
1536         float nearclip, farclip, bias;
1537         r_viewport_t viewport;
1538         int flipped;
1539
1540         if (r_shadow_rendermode != R_SHADOW_RENDERMODE_SHADOWMAP2D)
1541         {
1542                 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1543
1544                 R_Mesh_ResetTextureState();
1545                 R_Shadow_RenderMode_Reset();
1546                 if (r_shadow_shadowmap2ddepthbuffer)
1547                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
1548                 else
1549                         R_Mesh_SetRenderTargets(r_shadow_fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
1550                 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
1551                 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
1552                 GL_DepthMask(true);
1553                 GL_DepthTest(true);
1554         }
1555
1556         nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1557         farclip = 1.0f;
1558         bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1559
1560         R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL, x, y);
1561         R_SetViewport(&viewport);
1562         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1563         flipped = (side & 1) ^ (side >> 2);
1564         r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
1565         r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
1566
1567         if (r_shadow_shadowmap2ddepthbuffer)
1568                 GL_ColorMask(1,1,1,1);
1569         else
1570                 GL_ColorMask(0,0,0,0);
1571         switch(vid.renderpath)
1572         {
1573         case RENDERPATH_GL32:
1574         case RENDERPATH_GLES2:
1575                 GL_CullFace(r_refdef.view.cullface_back);
1576                 break;
1577         }
1578
1579         // used in R_Q1BSP_DrawShadowMap code to check surfacesides[]
1580         r_shadow_shadowmapside = side;
1581 }
1582
1583 void R_Shadow_RenderMode_Lighting(qboolean transparent, qboolean shadowmapping, qboolean noselfshadowpass)
1584 {
1585         R_Mesh_ResetTextureState();
1586         if (transparent)
1587         {
1588                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1589                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1590                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1591                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1592         }
1593         if (shadowmapping)
1594                 R_Shadow_SetShadowmapParametersForLight(noselfshadowpass);
1595         R_Shadow_RenderMode_Reset();
1596         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1597         if (!transparent)
1598                 GL_DepthFunc(GL_EQUAL);
1599         // do global setup needed for the chosen lighting mode
1600         if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1601                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1602         r_shadow_usingshadowmap2d = shadowmapping;
1603         r_shadow_rendermode = r_shadow_lightingrendermode;
1604 }
1605
1606 static const unsigned short bboxelements[36] =
1607 {
1608         5, 1, 3, 5, 3, 7,
1609         6, 2, 0, 6, 0, 4,
1610         7, 3, 2, 7, 2, 6,
1611         4, 0, 1, 4, 1, 5,
1612         4, 5, 7, 4, 7, 6,
1613         1, 0, 2, 1, 2, 3,
1614 };
1615
1616 static const float bboxpoints[8][3] =
1617 {
1618         {-1,-1,-1},
1619         { 1,-1,-1},
1620         {-1, 1,-1},
1621         { 1, 1,-1},
1622         {-1,-1, 1},
1623         { 1,-1, 1},
1624         {-1, 1, 1},
1625         { 1, 1, 1},
1626 };
1627
1628 void R_Shadow_RenderMode_DrawDeferredLight(qboolean shadowmapping)
1629 {
1630         int i;
1631         float vertex3f[8*3];
1632         const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
1633 // do global setup needed for the chosen lighting mode
1634         R_Shadow_RenderMode_Reset();
1635         r_shadow_rendermode = r_shadow_lightingrendermode;
1636         R_EntityMatrix(&identitymatrix);
1637         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1638         if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
1639                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
1640         else
1641                 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
1642
1643         r_shadow_usingshadowmap2d = shadowmapping;
1644
1645         // render the lighting
1646         R_SetupShader_DeferredLight(rsurface.rtlight);
1647         for (i = 0;i < 8;i++)
1648                 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
1649         GL_ColorMask(1,1,1,1);
1650         GL_DepthMask(false);
1651         GL_DepthRange(0, 1);
1652         GL_PolygonOffset(0, 0);
1653         GL_DepthTest(true);
1654         GL_DepthFunc(GL_GREATER);
1655         GL_CullFace(r_refdef.view.cullface_back);
1656         R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
1657         R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
1658 }
1659
1660 static qboolean R_Shadow_BounceGrid_CheckEnable(int flag)
1661 {
1662         qboolean enable = r_shadow_bouncegrid_state.capable && r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
1663         int lightindex;
1664         int range;
1665         dlight_t *light;
1666         rtlight_t *rtlight;
1667         vec3_t lightcolor;
1668
1669         // see if there are really any lights to render...
1670         if (enable && r_shadow_bouncegrid_static.integer)
1671         {
1672                 enable = false;
1673                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1674                 for (lightindex = 0;lightindex < range;lightindex++)
1675                 {
1676                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1677                         if (!light || !(light->flags & flag))
1678                                 continue;
1679                         rtlight = &light->rtlight;
1680                         // when static, we skip styled lights because they tend to change...
1681                         if (rtlight->style > 0)
1682                                 continue;
1683                         VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
1684                         if (!VectorLength2(lightcolor))
1685                                 continue;
1686                         enable = true;
1687                         break;
1688                 }
1689         }
1690
1691         return enable;
1692 }
1693
1694 static void R_Shadow_BounceGrid_GenerateSettings(r_shadow_bouncegrid_settings_t *settings)
1695 {
1696         qboolean s = r_shadow_bouncegrid_static.integer != 0;
1697         float spacing = bound(1.0f, s ? r_shadow_bouncegrid_static_spacing.value : r_shadow_bouncegrid_dynamic_spacing.value, 1024.0f);
1698         float quality = bound(0.0001f, (s ? r_shadow_bouncegrid_static_quality.value : r_shadow_bouncegrid_dynamic_quality.value), 1024.0f);
1699         float bounceminimumintensity = s ? r_shadow_bouncegrid_static_bounceminimumintensity.value : r_shadow_bouncegrid_dynamic_bounceminimumintensity.value;
1700
1701         // prevent any garbage in alignment padded areas as we'll be using memcmp
1702         memset(settings, 0, sizeof(*settings));
1703
1704         // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
1705         settings->staticmode                    = s;
1706         settings->blur                          = r_shadow_bouncegrid_blur.integer != 0;
1707         settings->floatcolors                   = bound(0, r_shadow_bouncegrid_floatcolors.integer, 2);
1708         settings->lightpathsize                 = bound(0.0f, r_shadow_bouncegrid_lightpathsize.value, 1024.0f);
1709         settings->directionalshading            = (s ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_dynamic_directionalshading.integer != 0) && r_shadow_bouncegrid_state.allowdirectionalshading;
1710         settings->dlightparticlemultiplier      = s ? 0 : r_shadow_bouncegrid_dynamic_dlightparticlemultiplier.value;
1711         settings->hitmodels                     = s ? false : r_shadow_bouncegrid_dynamic_hitmodels.integer != 0;
1712         settings->includedirectlighting         = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
1713         settings->lightradiusscale              = (s ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_dynamic_lightradiusscale.value);
1714         settings->maxbounce                     = (s ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_dynamic_maxbounce.integer);
1715         settings->particlebounceintensity       = r_shadow_bouncegrid_particlebounceintensity.value;
1716         settings->particleintensity             = r_shadow_bouncegrid_particleintensity.value * (settings->directionalshading ? 4.0f : 1.0f) / 65536.0f;
1717         settings->maxphotons                    = s ? r_shadow_bouncegrid_static_maxphotons.integer : r_shadow_bouncegrid_dynamic_maxphotons.integer;
1718         settings->energyperphoton               = 4096.0f / quality;
1719         settings->spacing[0]                    = spacing;
1720         settings->spacing[1]                    = spacing;
1721         settings->spacing[2]                    = spacing;
1722         settings->rng_type                      = r_shadow_bouncegrid_rng_type.integer;
1723         settings->rng_seed                      = r_shadow_bouncegrid_rng_seed.integer;
1724         settings->bounceminimumintensity2       = bounceminimumintensity * bounceminimumintensity;
1725         settings->normalizevectors              = r_shadow_bouncegrid_normalizevectors.integer != 0;
1726         settings->subsamples                    = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1727
1728         // bound the values for sanity
1729         settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1730         settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1731         settings->maxbounce = bound(0, settings->maxbounce, 16);
1732         settings->spacing[0] = bound(1, settings->spacing[0], 512);
1733         settings->spacing[1] = bound(1, settings->spacing[1], 512);
1734         settings->spacing[2] = bound(1, settings->spacing[2], 512);
1735 }
1736
1737 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1738 {
1739         float m[16];
1740         int c[4];
1741         int resolution[3];
1742         int numpixels;
1743         vec3_t ispacing;
1744         vec3_t maxs;
1745         vec3_t mins;
1746         vec3_t size;
1747         vec3_t spacing;
1748         r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1749
1750         // get the spacing values
1751         spacing[0] = settings->spacing[0];
1752         spacing[1] = settings->spacing[1];
1753         spacing[2] = settings->spacing[2];
1754         ispacing[0] = 1.0f / spacing[0];
1755         ispacing[1] = 1.0f / spacing[1];
1756         ispacing[2] = 1.0f / spacing[2];
1757
1758         // calculate texture size enclosing entire world bounds at the spacing
1759         if (r_refdef.scene.worldmodel)
1760         {
1761                 int lightindex;
1762                 int range;
1763                 qboolean bounds_set = false;
1764                 dlight_t *light;
1765                 rtlight_t *rtlight;
1766
1767                 // calculate bounds enclosing world lights as they should be noticably tighter 
1768                 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1769                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1770                 for (lightindex = 0;lightindex < range;lightindex++)
1771                 {
1772                         const vec_t *rtlmins, *rtlmaxs;
1773
1774                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1775                         if (!light)
1776                                 continue;
1777
1778                         rtlight = &light->rtlight;
1779                         rtlmins = rtlight->cullmins;
1780                         rtlmaxs = rtlight->cullmaxs;
1781
1782                         if (!bounds_set)
1783                         {
1784                                 VectorCopy(rtlmins, mins);
1785                                 VectorCopy(rtlmaxs, maxs);
1786                                 bounds_set = true;
1787                         }
1788                         else
1789                         {
1790                                 mins[0] = min(mins[0], rtlmins[0]);
1791                                 mins[1] = min(mins[1], rtlmins[1]);
1792                                 mins[2] = min(mins[2], rtlmins[2]);
1793                                 maxs[0] = max(maxs[0], rtlmaxs[0]);
1794                                 maxs[1] = max(maxs[1], rtlmaxs[1]);
1795                                 maxs[2] = max(maxs[2], rtlmaxs[2]);
1796                         }
1797                 }
1798
1799                 // limit to no larger than the world bounds
1800                 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1801                 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1802                 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1803                 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1804                 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1805                 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1806
1807                 VectorMA(mins, -2.0f, spacing, mins);
1808                 VectorMA(maxs, 2.0f, spacing, maxs);
1809         }
1810         else
1811         {
1812                 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1813                 VectorSet(maxs,  1048576.0f,  1048576.0f,  1048576.0f);
1814         }
1815         VectorSubtract(maxs, mins, size);
1816         // now we can calculate the resolution we want
1817         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1818         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1819         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1820         // figure out the exact texture size (honoring power of 2 if required)
1821         resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1822         resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1823         resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1824         size[0] = spacing[0] * resolution[0];
1825         size[1] = spacing[1] * resolution[1];
1826         size[2] = spacing[2] * resolution[2];
1827
1828         // if dynamic we may or may not want to use the world bounds
1829         // if the dynamic size is smaller than the world bounds, use it instead
1830         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]))
1831         {
1832                 // we know the resolution we want
1833                 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1834                 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1835                 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1836                 // now we can calculate the texture size
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                 // center the rendering on the view
1844                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1845                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1846                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1847         }
1848
1849         // recalculate the maxs in case the resolution was not satisfactory
1850         VectorAdd(mins, size, maxs);
1851
1852         // check if this changed the texture size
1853         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);
1854         r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1855         VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1856         VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1857         VectorCopy(size, r_shadow_bouncegrid_state.size);
1858         VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1859         VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1860         VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1861
1862         // reallocate pixels for this update if needed...
1863         r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1864         r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1865         r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1866         numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1867         if (r_shadow_bouncegrid_state.numpixels != numpixels)
1868         {
1869                 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1870
1871                 r_shadow_bouncegrid_state.highpixels = NULL;
1872
1873                 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1874                 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1875                 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1876                 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1877                 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1878                 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1879                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1880
1881                 r_shadow_bouncegrid_state.numpixels = numpixels;
1882         }
1883
1884         // update the bouncegrid matrix to put it in the world properly
1885         memset(m, 0, sizeof(m));
1886         m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1887         m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1888         m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1889         m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1890         m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1891         m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1892         m[15] = 1.0f;
1893         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1894 }
1895
1896 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1897 {
1898         // check material at shadoworigin to see what the initial refractive index should be
1899         int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1900         int skipsupercontentsmask = 0;
1901         int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1902         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);
1903         if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1904                 return trace.starttexture->refractive_index;
1905         else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1906                 return 1.333f; // water
1907         else
1908                 return 1.0003f; // air
1909 }
1910
1911 // enumerate world rtlights and sum the overall amount of light in the world,
1912 // from that we can calculate a scaling factor to fairly distribute photons
1913 // to all the lights
1914 //
1915 // this modifies rtlight->photoncolor and rtlight->photons
1916 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1917 {
1918         // get the range of light numbers we'll be looping over:
1919         // range = static lights
1920         // range1 = dynamic lights (optional)
1921         // range2 = range + range1
1922         unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1923         unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1924         unsigned int range2 = range + range1;
1925         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1926
1927         float normalphotonscaling;
1928         float photonscaling;
1929         float photonintensity;
1930         float photoncount = 0.0f;
1931         float lightintensity;
1932         float radius;
1933         float s;
1934         float w;
1935         vec3_t cullmins;
1936         vec3_t cullmaxs;
1937         unsigned int lightindex;
1938         dlight_t *light;
1939         rtlight_t *rtlight;
1940         int shootparticles;
1941         int shotparticles;
1942         float bounceminimumintensity2;
1943         float startrefractiveindex;
1944         unsigned int seed;
1945         randomseed_t randomseed;
1946         vec3_t baseshotcolor;
1947
1948         normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1949         for (lightindex = 0;lightindex < range2;lightindex++)
1950         {
1951                 if (lightindex < range)
1952                 {
1953                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1954                         if (!light)
1955                                 continue;
1956                         rtlight = &light->rtlight;
1957                         VectorClear(rtlight->bouncegrid_photoncolor);
1958                         rtlight->bouncegrid_photons = 0;
1959                         rtlight->bouncegrid_hits = 0;
1960                         rtlight->bouncegrid_traces = 0;
1961                         rtlight->bouncegrid_effectiveradius = 0;
1962                         if (!(light->flags & flag))
1963                                 continue;
1964                         if (r_shadow_bouncegrid_state.settings.staticmode)
1965                         {
1966                                 // when static, we skip styled lights because they tend to change...
1967                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1968                                         continue;
1969                         }
1970                         else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1971                                 continue;
1972                 }
1973                 else
1974                 {
1975                         rtlight = r_refdef.scene.lights[lightindex - range];
1976                         VectorClear(rtlight->bouncegrid_photoncolor);
1977                         rtlight->bouncegrid_photons = 0;
1978                         rtlight->bouncegrid_hits = 0;
1979                         rtlight->bouncegrid_traces = 0;
1980                         rtlight->bouncegrid_effectiveradius = 0;
1981                 }
1982                 // draw only visible lights (major speedup)
1983                 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1984                 cullmins[0] = rtlight->shadoworigin[0] - radius;
1985                 cullmins[1] = rtlight->shadoworigin[1] - radius;
1986                 cullmins[2] = rtlight->shadoworigin[2] - radius;
1987                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1988                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1989                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1990                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1991                 if (!r_shadow_bouncegrid_state.settings.staticmode)
1992                 {
1993                         // skip if the expanded light box does not touch any visible leafs
1994                         if (r_refdef.scene.worldmodel
1995                                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
1996                                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
1997                                 continue;
1998                         // skip if the expanded light box is not visible to traceline
1999                         // note that PrepareLight already did this check but for a smaller box, so we
2000                         // end up casting more traces per frame per light when using bouncegrid, which
2001                         // is probably fine (and they use the same timer)
2002                         if (r_shadow_culllights_trace.integer)
2003                         {
2004                                 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
2005                                         rtlight->trace_timer = realtime;
2006                                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2007                                         continue;
2008                         }
2009                         // skip if expanded light box is offscreen
2010                         if (R_CullBox(cullmins, cullmaxs))
2011                                 continue;
2012                         // skip if overall light intensity is zero
2013                         if (w * VectorLength2(rtlight->color) == 0.0f)
2014                                 continue;
2015                 }
2016                 // a light that does not emit any light before style is applied, can be
2017                 // skipped entirely (it may just be a corona)
2018                 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2019                         continue;
2020                 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2021                 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2022                 // skip lights that will emit no photons
2023                 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2024                         continue;
2025                 // shoot particles from this light
2026                 // use a calculation for the number of particles that will not
2027                 // vary with lightstyle, otherwise we get randomized particle
2028                 // distribution, the seeded random is only consistent for a
2029                 // consistent number of particles on this light...
2030                 s = rtlight->radius;
2031                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2032                 if (lightindex >= range)
2033                         lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2034                 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2035                 photoncount += rtlight->bouncegrid_photons;
2036                 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2037                 // if the lightstyle happens to be off right now, we can skip actually
2038                 // firing the photons, but we did have to count them in the total.
2039                 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2040                 //      rtlight->bouncegrid_photons = 0;
2041         }
2042         // the user provided an energyperphoton value which we try to use
2043         // if that results in too many photons to shoot this frame, then we cap it
2044         // which causes photons to appear/disappear from frame to frame, so we don't
2045         // like doing that in the typical case
2046         photonscaling = 1.0f;
2047         photonintensity = 1.0f;
2048         if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2049         {
2050                 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2051                 photonintensity = 1.0f / photonscaling;
2052         }
2053
2054         // modify the lights to reflect our computed scaling
2055         for (lightindex = 0; lightindex < range2; lightindex++)
2056         {
2057                 if (lightindex < range)
2058                 {
2059                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2060                         if (!light)
2061                                 continue;
2062                         rtlight = &light->rtlight;
2063                 }
2064                 else
2065                         rtlight = r_refdef.scene.lights[lightindex - range];
2066                 rtlight->bouncegrid_photons *= photonscaling;
2067                 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2068         }
2069
2070         // compute a seed for the unstable random modes
2071         Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2072         seed = realtime * 1000.0;
2073
2074         for (lightindex = 0; lightindex < range2; lightindex++)
2075         {
2076                 if (lightindex < range)
2077                 {
2078                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2079                         if (!light)
2080                                 continue;
2081                         rtlight = &light->rtlight;
2082                 }
2083                 else
2084                         rtlight = r_refdef.scene.lights[lightindex - range];
2085                 // note that this code used to keep track of residual photons and
2086                 // distribute them evenly to achieve exactly a desired photon count,
2087                 // but that caused unwanted flickering in dynamic mode
2088                 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2089                 // skip if we won't be shooting any photons
2090                 if (!shootparticles)
2091                         continue;
2092                 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2093                 //s = settings.particleintensity / shootparticles;
2094                 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2095                 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2096                 if (VectorLength2(baseshotcolor) <= 0.0f)
2097                         continue;
2098                 r_refdef.stats[r_stat_bouncegrid_lights]++;
2099                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2100                 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2101                 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2102
2103                 // check material at shadoworigin to see what the initial refractive index should be
2104                 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2105
2106                 // for seeded random we start the RNG with the position of the light
2107                 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2108                 {
2109                         union
2110                         {
2111                                 unsigned int i[4];
2112                                 float f[4];
2113                         }
2114                         u;
2115                         u.f[0] = rtlight->shadoworigin[0];
2116                         u.f[1] = rtlight->shadoworigin[1];
2117                         u.f[2] = rtlight->shadoworigin[2];
2118                         u.f[3] = 1;
2119                         switch (r_shadow_bouncegrid_state.settings.rng_type)
2120                         {
2121                         default:
2122                         case 0:
2123                                 // we have to shift the seed provided by the user because the result must be odd
2124                                 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2125                                 break;
2126                         case 1:
2127                                 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2128                                 break;
2129                         }
2130                 }
2131
2132                 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2133                 {
2134                         r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2135                         VectorCopy(baseshotcolor, p->color);
2136                         VectorCopy(rtlight->shadoworigin, p->start);
2137                         switch (r_shadow_bouncegrid_state.settings.rng_type)
2138                         {
2139                         default:
2140                         case 0:
2141                                 // figure out a random direction for the initial photon to go
2142                                 VectorLehmerRandom(&randomseed, p->end);
2143                                 break;
2144                         case 1:
2145                                 // figure out a random direction for the initial photon to go
2146                                 VectorCheeseRandom(seed, p->end);
2147                                 break;
2148                         }
2149
2150                         // we want a uniform distribution spherically, not merely within the sphere
2151                         if (r_shadow_bouncegrid_state.settings.normalizevectors)
2152                                 VectorNormalize(p->end);
2153
2154                         VectorMA(p->start, radius, p->end, p->end);
2155                         p->bounceminimumintensity2 = bounceminimumintensity2;
2156                         p->startrefractiveindex = startrefractiveindex;
2157                         p->numpaths = 0;
2158                 }
2159         }
2160
2161         t->done = 1;
2162 }
2163
2164 static void R_Shadow_BounceGrid_Slice(int zi)
2165 {
2166         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2167         int xi, yi; // pixel increments
2168         float color[32] = { 0 };
2169         float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2170         float iradius = 1.0f / radius;
2171         int slicemins[3], slicemaxs[3];
2172         int resolution[3];
2173         int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2174         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2175         int photonindex;
2176         int samples = r_shadow_bouncegrid_state.settings.subsamples;
2177         float isamples = 1.0f / samples;
2178         float samplescolorscale = isamples * isamples * isamples;
2179
2180         // we use these a lot, so get a local copy
2181         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2182
2183         for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2184         {
2185                 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2186                 int pathindex;
2187                 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2188                 {
2189                         r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2190                         float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2191
2192                         VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2193                         VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2194
2195                         pathmins[2] = min(pathstart[2], pathend[2]);
2196                         slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2197                         pathmaxs[2] = max(pathstart[2], pathend[2]);
2198                         slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2199
2200                         // skip if the path doesn't touch this slice
2201                         if (zi < slicemins[2] || zi >= slicemaxs[2])
2202                                 continue;
2203
2204                         pathmins[0] = min(pathstart[0], pathend[0]);
2205                         slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2206                         slicemins[0] = max(slicemins[0], 1);
2207                         pathmaxs[0] = max(pathstart[0], pathend[0]);
2208                         slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2209                         slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2210
2211                         pathmins[1] = min(pathstart[1], pathend[1]);
2212                         slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2213                         slicemins[1] = max(slicemins[1], 1);
2214                         pathmaxs[1] = max(pathstart[1], pathend[1]);
2215                         slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2216                         slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2217
2218                         // skip if the path is out of bounds on X or Y
2219                         if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2220                                 continue;
2221
2222                         // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2223                         // accumulate average shotcolor
2224                         VectorSubtract(pathend, pathstart, pathdelta);
2225                         pathlength2 = VectorLength2(pathdelta);
2226                         pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2227                         VectorScale(pathdelta, pathilength, pathdir);
2228                         // the color is scaled by the number of subsamples
2229                         color[0] = path->color[0] * samplescolorscale;
2230                         color[1] = path->color[1] * samplescolorscale;
2231                         color[2] = path->color[2] * samplescolorscale;
2232                         color[3] = 0.0f;
2233                         if (pixelbands > 1)
2234                         {
2235                                 // store bentnormal in case the shader has a use for it,
2236                                 // bentnormal is an intensity-weighted average of the directions,
2237                                 // and will be normalized on conversion to texture pixels.
2238                                 float intensity = VectorLength(color);
2239                                 color[4] = pathdir[0] * intensity;
2240                                 color[5] = pathdir[1] * intensity;
2241                                 color[6] = pathdir[2] * intensity;
2242                                 color[7] = intensity;
2243                                 // for each color component (R, G, B) calculate the amount that a
2244                                 // direction contributes
2245                                 color[8] = color[0] * max(0.0f, pathdir[0]);
2246                                 color[9] = color[0] * max(0.0f, pathdir[1]);
2247                                 color[10] = color[0] * max(0.0f, pathdir[2]);
2248                                 color[11] = 0.0f;
2249                                 color[12] = color[1] * max(0.0f, pathdir[0]);
2250                                 color[13] = color[1] * max(0.0f, pathdir[1]);
2251                                 color[14] = color[1] * max(0.0f, pathdir[2]);
2252                                 color[15] = 0.0f;
2253                                 color[16] = color[2] * max(0.0f, pathdir[0]);
2254                                 color[17] = color[2] * max(0.0f, pathdir[1]);
2255                                 color[18] = color[2] * max(0.0f, pathdir[2]);
2256                                 color[19] = 0.0f;
2257                                 // and do the same for negative directions
2258                                 color[20] = color[0] * max(0.0f, -pathdir[0]);
2259                                 color[21] = color[0] * max(0.0f, -pathdir[1]);
2260                                 color[22] = color[0] * max(0.0f, -pathdir[2]);
2261                                 color[23] = 0.0f;
2262                                 color[24] = color[1] * max(0.0f, -pathdir[0]);
2263                                 color[25] = color[1] * max(0.0f, -pathdir[1]);
2264                                 color[26] = color[1] * max(0.0f, -pathdir[2]);
2265                                 color[27] = 0.0f;
2266                                 color[28] = color[2] * max(0.0f, -pathdir[0]);
2267                                 color[29] = color[2] * max(0.0f, -pathdir[1]);
2268                                 color[30] = color[2] * max(0.0f, -pathdir[2]);
2269                                 color[31] = 0.0f;
2270                         }
2271
2272                         for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2273                         {
2274                                 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2275                                 {
2276                                         float sample[3], diff[3], nearest[3], along, distance2;
2277                                         float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2278                                         int xs, ys, zs;
2279                                         // loop over the subsamples
2280                                         for (zs = 0; zs < samples; zs++)
2281                                         {
2282                                                 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2283                                                 for (ys = 0; ys < samples; ys++)
2284                                                 {
2285                                                         sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2286                                                         for (xs = 0; xs < samples; xs++)
2287                                                         {
2288                                                                 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2289
2290                                                                 // measure distance from subsample to line segment and see if it is within radius
2291                                                                 along = DotProduct(sample, pathdir) * pathilength;
2292                                                                 if (along <= 0)
2293                                                                         VectorCopy(pathstart, nearest);
2294                                                                 else if (along >= 1)
2295                                                                         VectorCopy(pathend, nearest);
2296                                                                 else
2297                                                                         VectorLerp(pathstart, along, pathend, nearest);
2298                                                                 VectorSubtract(sample, nearest, diff);
2299                                                                 VectorScale(diff, iradius, diff);
2300                                                                 distance2 = VectorLength2(diff);
2301                                                                 if (distance2 < 1.0f)
2302                                                                 {
2303                                                                         // contribute some color to this pixel, across all bands
2304                                                                         float w = 1.0f - sqrt(distance2);
2305                                                                         int band;
2306                                                                         w *= w;
2307                                                                         if (pixelbands > 1)
2308                                                                         {
2309                                                                                 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2310                                                                                 p[pixelsperband * 4 + 3] += color[7] * w;
2311                                                                         }
2312                                                                         for (band = 0; band < pixelbands; band++)
2313                                                                         {
2314                                                                                 // add to the pixel color (RGB only - see above)
2315                                                                                 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2316                                                                                 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2317                                                                                 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2318                                                                         }
2319                                                                 }
2320                                                         }
2321                                                 }
2322                                         }
2323                                 }
2324                         }
2325                 }
2326         }
2327 }
2328
2329 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2330 {
2331         R_Shadow_BounceGrid_Slice((int)t->i[0]);
2332         t->done = 1;
2333 }
2334
2335 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2336 {
2337         int i, slices;
2338         // we need to wait for the texture clear to finish before we start adding light to it
2339         if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2340         {
2341                 TaskQueue_Yield(t);
2342                 return;
2343         }
2344         slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2345         for (i = 0; i < slices; i++)
2346                 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2347         TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2348         TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2349         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2350         t->done = 1;
2351 }
2352
2353 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2354 {
2355         const float *inpixel;
2356         float *outpixel;
2357         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2358         int pixelband;
2359         unsigned int index;
2360         unsigned int x, y, z;
2361         unsigned int resolution[3];
2362         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2363         for (pixelband = 0;pixelband < pixelbands;pixelband++)
2364         {
2365                 for (z = 1;z < resolution[2]-1;z++)
2366                 {
2367                         for (y = 1;y < resolution[1]-1;y++)
2368                         {
2369                                 x = 1;
2370                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2371                                 inpixel = inpixels + 4*index;
2372                                 outpixel = outpixels + 4*index;
2373                                 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2374                                 {
2375                                         outpixel[0] = (inpixel[0] + inpixel[  off] + inpixel[0-off]) * (1.0f / 3.0);
2376                                         outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2377                                         outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2378                                         outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2379                                 }
2380                         }
2381                 }
2382         }
2383 }
2384
2385 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2386 {
2387         float *pixels[4];
2388         unsigned int resolution[3];
2389         if (r_shadow_bouncegrid_state.settings.blur)
2390         {
2391                 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2392
2393                 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2394                 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2395                 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2396                 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2397
2398                 // blur on X
2399                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2400                 // blur on Y
2401                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2402                 // blur on Z
2403                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2404
2405                 // toggle the state, highpixels now points to pixels[3] result
2406                 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2407                 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2408         }
2409         t->done = 1;
2410 }
2411
2412 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2413 {
2414         int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2415         unsigned char *pixelsbgra8 = NULL;
2416         unsigned char *pixelbgra8;
2417         unsigned short *pixelsrgba16f = NULL;
2418         unsigned short *pixelrgba16f;
2419         float *pixelsrgba32f = NULL;
2420         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2421         float *highpixel;
2422         float *bandpixel;
2423         unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2424         unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2425         unsigned int pixelband;
2426         unsigned int x, y, z;
2427         unsigned int index, bandindex;
2428         unsigned int resolution[3];
2429         int c[4];
2430         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2431
2432         if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2433         {
2434                 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2435                 r_shadow_bouncegrid_state.texture = NULL;
2436         }
2437
2438         // if bentnormals exist, we need to normalize and bias them for the shader
2439         if (pixelbands > 1)
2440         {
2441                 pixelband = 1;
2442                 for (z = 0;z < resolution[2]-1;z++)
2443                 {
2444                         for (y = 0;y < resolution[1]-1;y++)
2445                         {
2446                                 x = 1;
2447                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2448                                 highpixel = highpixels + 4*index;
2449                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2450                                 {
2451                                         // only convert pixels that were hit by photons
2452                                         if (highpixel[3] != 0.0f)
2453                                                 VectorNormalize(highpixel);
2454                                         VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2455                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2456                                 }
2457                         }
2458                 }
2459         }
2460
2461         // start by clearing the pixels array - we won't be writing to all of it
2462         //
2463         // then process only the pixels that have at least some color, skipping
2464         // the higher bands for speed on pixels that are black
2465         switch (floatcolors)
2466         {
2467         case 0:
2468                 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2469                         r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2470                 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2471                 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2472                 {
2473                         if (pixelband == 1)
2474                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2475                         else
2476                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2477                 }
2478                 for (z = 1;z < resolution[2]-1;z++)
2479                 {
2480                         for (y = 1;y < resolution[1]-1;y++)
2481                         {
2482                                 x = 1;
2483                                 pixelband = 0;
2484                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2485                                 highpixel = highpixels + 4*index;
2486                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2487                                 {
2488                                         // only convert pixels that were hit by photons
2489                                         if (VectorLength2(highpixel))
2490                                         {
2491                                                 // normalize the bentnormal now
2492                                                 if (pixelbands > 1)
2493                                                 {
2494                                                         VectorNormalize(highpixel + pixelsperband * 4);
2495                                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2496                                                 }
2497                                                 // process all of the pixelbands for this pixel
2498                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2499                                                 {
2500                                                         pixelbgra8 = pixelsbgra8 + 4*bandindex;
2501                                                         bandpixel = highpixels + 4*bandindex;
2502                                                         c[0] = (int)(bandpixel[0]*256.0f);
2503                                                         c[1] = (int)(bandpixel[1]*256.0f);
2504                                                         c[2] = (int)(bandpixel[2]*256.0f);
2505                                                         c[3] = (int)(bandpixel[3]*256.0f);
2506                                                         pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2507                                                         pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2508                                                         pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2509                                                         pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2510                                                 }
2511                                         }
2512                                 }
2513                         }
2514                 }
2515
2516                 if (!r_shadow_bouncegrid_state.createtexture)
2517                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2518                 else
2519                         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);
2520                 break;
2521         case 1:
2522                 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2523                         r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2524                 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2525                 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2526                 for (z = 1;z < resolution[2]-1;z++)
2527                 {
2528                         for (y = 1;y < resolution[1]-1;y++)
2529                         {
2530                                 x = 1;
2531                                 pixelband = 0;
2532                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2533                                 highpixel = highpixels + 4*index;
2534                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2535                                 {
2536                                         // only convert pixels that were hit by photons
2537                                         if (VectorLength2(highpixel))
2538                                         {
2539                                                 // process all of the pixelbands for this pixel
2540                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2541                                                 {
2542                                                         // time to have fun with IEEE 754 bit hacking...
2543                                                         union {
2544                                                                 float f[4];
2545                                                                 unsigned int raw[4];
2546                                                         } u;
2547                                                         pixelrgba16f = pixelsrgba16f + 4*bandindex;
2548                                                         bandpixel = highpixels + 4*bandindex;
2549                                                         VectorCopy4(bandpixel, u.f);
2550                                                         VectorCopy4(u.raw, c);
2551                                                         // this math supports negative numbers, snaps denormals to zero
2552                                                         //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2553                                                         //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2554                                                         //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2555                                                         //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2556                                                         // this math does not support negative
2557                                                         pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2558                                                         pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2559                                                         pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2560                                                         pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2561                                                 }
2562                                         }
2563                                 }
2564                         }
2565                 }
2566
2567                 if (!r_shadow_bouncegrid_state.createtexture)
2568                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2569                 else
2570                         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);
2571                 break;
2572         case 2:
2573                 // our native format happens to match, so this is easy.
2574                 pixelsrgba32f = highpixels;
2575
2576                 if (!r_shadow_bouncegrid_state.createtexture)
2577                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2578                 else
2579                         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);
2580                 break;
2581         }
2582
2583         r_shadow_bouncegrid_state.lastupdatetime = realtime;
2584 }
2585
2586 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2587 {
2588         memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2589         t->done = 1;
2590 }
2591
2592 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)
2593 {
2594         int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2595         vec3_t shothit;
2596         vec3_t surfacenormal;
2597         vec3_t reflectstart, reflectend, reflectcolor;
2598         vec3_t refractstart, refractend, refractcolor;
2599         vec_t s;
2600         float reflectamount = 1.0f;
2601         trace_t cliptrace;
2602         // figure out what we want to interact with
2603         hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2604         skipsupercontentsmask = 0;
2605         skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2606         //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2607         //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2608         if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2609         {
2610                 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2611                 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2612                 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);
2613         }
2614         else
2615         {
2616                 // dynamic mode fires many rays and most will match the cache from the previous frame
2617                 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);
2618         }
2619         VectorCopy(cliptrace.endpos, shothit);
2620         if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2621         {
2622                 qboolean notculled = true;
2623                 // cull paths that fail R_CullBox in dynamic mode
2624                 if (!r_shadow_bouncegrid_state.settings.staticmode
2625                         && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2626                 {
2627                         vec3_t cullmins, cullmaxs;
2628                         cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2629                         cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2630                         cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2631                         cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2632                         cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2633                         cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2634                         if (R_CullBox(cullmins, cullmaxs))
2635                                 notculled = false;
2636                 }
2637                 if (notculled)
2638                 {
2639                         r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2640                         VectorCopy(shotstart, path->start);
2641                         VectorCopy(shothit, path->end);
2642                         VectorCopy(shotcolor, path->color);
2643                 }
2644         }
2645         if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2646         {
2647                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2648                 // also clamp the resulting color to never add energy, even if the user requests extreme values
2649                 VectorCopy(cliptrace.plane.normal, surfacenormal);
2650                 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2651                 VectorClear(refractcolor);
2652                 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2653                 if (cliptrace.hittexture)
2654                 {
2655                         if (cliptrace.hittexture->currentskinframe)
2656                                 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2657                         if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2658                         {
2659                                 reflectamount *= cliptrace.hittexture->currentalpha;
2660                                 if (cliptrace.hittexture->currentskinframe)
2661                                         reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2662                         }
2663                         if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2664                         {
2665                                 float Fresnel;
2666                                 vec3_t lightdir;
2667                                 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2668                                 VectorSubtract(shotstart, shotend, lightdir);
2669                                 VectorNormalize(lightdir);
2670                                 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2671                                 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2672                                 reflectamount *= Fresnel;
2673                                 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2674                         }
2675                         if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2676                                 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2677                         // make sure we do not gain energy even if surface colors are out of bounds
2678                         reflectcolor[0] = min(reflectcolor[0], 1.0f);
2679                         reflectcolor[1] = min(reflectcolor[1], 1.0f);
2680                         reflectcolor[2] = min(reflectcolor[2], 1.0f);
2681                         refractcolor[0] = min(refractcolor[0], 1.0f);
2682                         refractcolor[1] = min(refractcolor[1], 1.0f);
2683                         refractcolor[2] = min(refractcolor[2], 1.0f);
2684                 }
2685                 // reflected and refracted shots
2686                 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2687                 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2688                 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2689                 VectorMultiply(refractcolor, shotcolor, refractcolor);
2690
2691                 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2692                 {
2693                         // reflect the remaining portion of the line across plane normal
2694                         VectorSubtract(shotend, shothit, reflectend);
2695                         VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2696                         // calculate the new line start and end
2697                         VectorCopy(shothit, reflectstart);
2698                         VectorAdd(reflectstart, reflectend, reflectend);
2699                         R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2700                 }
2701
2702                 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2703                 {
2704                         // Check what refractive index is on the other side
2705                         float refractiveindex;
2706                         VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2707                         refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2708                         // reflect the remaining portion of the line across plane normal
2709                         VectorSubtract(shotend, shothit, refractend);
2710                         s = refractiveindex / previousrefractiveindex;
2711                         VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2712                         // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2713                         // calculate the new line start and end
2714                         VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2715                         VectorAdd(refractstart, refractend, refractend);
2716                         R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2717                 }
2718         }
2719 }
2720
2721 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2722 {
2723         r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2724         R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2725         t->done = 1;
2726 }
2727
2728 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2729 {
2730         int i;
2731         for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2732                 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2733         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);
2734         if (r_shadow_bouncegrid_threaded.integer)
2735         {
2736                 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2737                 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2738         }
2739         else
2740         {
2741                 // when not threaded we still have to report task status
2742                 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2743                         r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2744                 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2745         }
2746         t->done = 1;
2747 }
2748
2749 void R_Shadow_UpdateBounceGridTexture(void)
2750 {
2751         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2752         r_shadow_bouncegrid_settings_t settings;
2753         qboolean enable = false;
2754         qboolean settingschanged;
2755
2756         enable = R_Shadow_BounceGrid_CheckEnable(flag);
2757         
2758         R_Shadow_BounceGrid_GenerateSettings(&settings);
2759         
2760         // changing intensity does not require an update
2761         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2762
2763         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2764
2765         // when settings change, we free everything as it is just simpler that way.
2766         if (settingschanged || !enable)
2767         {
2768                 // not enabled, make sure we free anything we don't need anymore.
2769                 if (r_shadow_bouncegrid_state.texture)
2770                 {
2771                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
2772                         r_shadow_bouncegrid_state.texture = NULL;
2773                 }
2774                 r_shadow_bouncegrid_state.highpixels = NULL;
2775                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2776                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2777                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2778                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2779                 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2780                 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2781                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2782                 r_shadow_bouncegrid_state.numpixels = 0;
2783                 r_shadow_bouncegrid_state.numphotons = 0;
2784                 r_shadow_bouncegrid_state.directional = false;
2785
2786                 if (!enable)
2787                         return;
2788         }
2789
2790         // if all the settings seem identical to the previous update, return
2791         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2792                 return;
2793
2794         // store the new settings
2795         r_shadow_bouncegrid_state.settings = settings;
2796
2797         R_Shadow_BounceGrid_UpdateSpacing();
2798
2799         // allocate the highpixels array we'll be accumulating light into
2800         if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2801                 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2802         if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2803                 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2804         r_shadow_bouncegrid_state.highpixels_index = 0;
2805         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2806
2807         // set up the tracking of photon data
2808         if (r_shadow_bouncegrid_state.photons == NULL)
2809                 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));
2810         if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2811                 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2812         r_shadow_bouncegrid_state.numphotons = 0;
2813
2814         // set up the tracking of slice tasks
2815         if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2816                 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2817
2818         memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2819         memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2820         memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2821         memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2822         memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2823         memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2824         memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2825         memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2826         memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2827
2828         // clear the texture
2829         TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2830         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2831
2832         // calculate weighting factors for distributing photons among the lights
2833         TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2834         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2835
2836         // enqueue tasks to trace the photons from lights
2837         TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2838         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2839
2840         // accumulate the light paths into texture
2841         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);
2842         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2843
2844         // apply a mild blur filter to the texture
2845         TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2846         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2847
2848         TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2849         R_TimeReport("bouncegrid_gen");
2850
2851         // convert the pixels to lower precision and upload the texture
2852         // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2853         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2854         R_TimeReport("bouncegrid_tex");
2855
2856         // after we compute the static lighting we don't need to keep the highpixels array around
2857         if (settings.staticmode)
2858         {
2859                 r_shadow_bouncegrid_state.highpixels = NULL;
2860                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2861                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2862                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2863                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2864                 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2865                 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2866                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2867         }
2868 }
2869
2870 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2871 {
2872         R_Shadow_RenderMode_Reset();
2873         GL_BlendFunc(GL_ONE, GL_ONE);
2874         GL_DepthRange(0, 1);
2875         GL_DepthTest(r_showlighting.integer < 2);
2876         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2877         if (!transparent)
2878                 GL_DepthFunc(GL_EQUAL);
2879         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2880 }
2881
2882 void R_Shadow_RenderMode_End(void)
2883 {
2884         R_Shadow_RenderMode_Reset();
2885         R_Shadow_RenderMode_ActiveLight(NULL);
2886         GL_DepthMask(true);
2887         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2888         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2889 }
2890
2891 int bboxedges[12][2] =
2892 {
2893         // top
2894         {0, 1}, // +X
2895         {0, 2}, // +Y
2896         {1, 3}, // Y, +X
2897         {2, 3}, // X, +Y
2898         // bottom
2899         {4, 5}, // +X
2900         {4, 6}, // +Y
2901         {5, 7}, // Y, +X
2902         {6, 7}, // X, +Y
2903         // verticals
2904         {0, 4}, // +Z
2905         {1, 5}, // X, +Z
2906         {2, 6}, // Y, +Z
2907         {3, 7}, // XY, +Z
2908 };
2909
2910 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2911 {
2912         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2913         {
2914                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2915                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2916                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2917                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2918                 return false;
2919         }
2920         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2921                 return true; // invisible
2922         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2923         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2924         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2925         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2926                 r_refdef.stats[r_stat_lights_scissored]++;
2927         return false;
2928 }
2929
2930 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2931 {
2932         // used to display how many times a surface is lit for level design purposes
2933         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2934         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2935         RSurf_DrawBatch();
2936 }
2937
2938 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])
2939 {
2940         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2941         R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2942         RSurf_DrawBatch();
2943 }
2944
2945 extern cvar_t gl_lightmaps;
2946 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2947 {
2948         qboolean negated;
2949         float ambientcolor[3], diffusecolor[3], specularcolor[3];
2950         VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2951         VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2952         VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2953         if (!r_shadow_usenormalmap.integer)
2954         {
2955                 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2956                 VectorClear(diffusecolor);
2957                 VectorClear(specularcolor);
2958         }
2959         VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2960         VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2961         VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2962         if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2963                 return;
2964         negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2965         if(negated)
2966         {
2967                 VectorNegate(ambientcolor, ambientcolor);
2968                 VectorNegate(diffusecolor, diffusecolor);
2969                 VectorNegate(specularcolor, specularcolor);
2970                 GL_BlendEquationSubtract(true);
2971         }
2972         RSurf_SetupDepthAndCulling();
2973         switch (r_shadow_rendermode)
2974         {
2975         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2976                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2977                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2978                 break;
2979         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2980                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2981                 break;
2982         default:
2983                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2984                 break;
2985         }
2986         if(negated)
2987                 GL_BlendEquationSubtract(false);
2988 }
2989
2990 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)
2991 {
2992         matrix4x4_t tempmatrix = *matrix;
2993         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2994
2995         // if this light has been compiled before, free the associated data
2996         R_RTLight_Uncompile(rtlight);
2997
2998         // clear it completely to avoid any lingering data
2999         memset(rtlight, 0, sizeof(*rtlight));
3000
3001         // copy the properties
3002         rtlight->matrix_lighttoworld = tempmatrix;
3003         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3004         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3005         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3006         VectorCopy(color, rtlight->color);
3007         rtlight->cubemapname[0] = 0;
3008         if (cubemapname && cubemapname[0])
3009                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3010         rtlight->shadow = shadow;
3011         rtlight->corona = corona;
3012         rtlight->style = style;
3013         rtlight->isstatic = isstatic;
3014         rtlight->coronasizescale = coronasizescale;
3015         rtlight->ambientscale = ambientscale;
3016         rtlight->diffusescale = diffusescale;
3017         rtlight->specularscale = specularscale;
3018         rtlight->flags = flags;
3019
3020         // compute derived data
3021         //rtlight->cullradius = rtlight->radius;
3022         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3023         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3024         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3025         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3026         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3027         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3028         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3029 }
3030
3031 // compiles rtlight geometry
3032 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3033 void R_RTLight_Compile(rtlight_t *rtlight)
3034 {
3035         int i;
3036         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3037         int lighttris, shadowtris;
3038         entity_render_t *ent = r_refdef.scene.worldentity;
3039         dp_model_t *model = r_refdef.scene.worldmodel;
3040         unsigned char *data;
3041
3042         // compile the light
3043         rtlight->compiled = true;
3044         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3045         rtlight->static_numleafs = 0;
3046         rtlight->static_numleafpvsbytes = 0;
3047         rtlight->static_leaflist = NULL;
3048         rtlight->static_leafpvs = NULL;
3049         rtlight->static_numsurfaces = 0;
3050         rtlight->static_surfacelist = NULL;
3051         rtlight->static_shadowmap_receivers = 0x3F;
3052         rtlight->static_shadowmap_casters = 0x3F;
3053         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3054         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3055         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3056         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3057         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3058         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3059
3060         if (model && model->GetLightInfo)
3061         {
3062                 // this variable must be set for the CompileShadowMap code
3063                 r_shadow_compilingrtlight = rtlight;
3064                 R_FrameData_SetMark();
3065                 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);
3066                 R_FrameData_ReturnToMark();
3067                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3068                 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3069                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3070                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3071                 rtlight->static_numsurfaces = numsurfaces;
3072                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3073                 rtlight->static_numleafs = numleafs;
3074                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3075                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3076                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3077                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3078                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3079                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3080                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3081                 if (rtlight->static_numsurfaces)
3082                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3083                 if (rtlight->static_numleafs)
3084                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3085                 if (rtlight->static_numleafpvsbytes)
3086                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3087                 if (rtlight->static_numshadowtrispvsbytes)
3088                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3089                 if (rtlight->static_numlighttrispvsbytes)
3090                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3091                 R_FrameData_SetMark();
3092                 if (model->CompileShadowMap && rtlight->shadow)
3093                         model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3094                 R_FrameData_ReturnToMark();
3095                 // now we're done compiling the rtlight
3096                 r_shadow_compilingrtlight = NULL;
3097         }
3098
3099
3100         // use smallest available cullradius - box radius or light radius
3101         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3102         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3103
3104         lighttris = 0;
3105         if (rtlight->static_numlighttrispvsbytes)
3106                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3107                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3108                                 lighttris++;
3109
3110         shadowtris = 0;
3111         if (rtlight->static_numshadowtrispvsbytes)
3112                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3113                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3114                                 shadowtris++;
3115
3116         if (developer_extra.integer)
3117                 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);
3118 }
3119
3120 void R_RTLight_Uncompile(rtlight_t *rtlight)
3121 {
3122         if (rtlight->compiled)
3123         {
3124                 if (rtlight->static_meshchain_shadow_shadowmap)
3125                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3126                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3127                 // these allocations are grouped
3128                 if (rtlight->static_surfacelist)
3129                         Mem_Free(rtlight->static_surfacelist);
3130                 rtlight->static_numleafs = 0;
3131                 rtlight->static_numleafpvsbytes = 0;
3132                 rtlight->static_leaflist = NULL;
3133                 rtlight->static_leafpvs = NULL;
3134                 rtlight->static_numsurfaces = 0;
3135                 rtlight->static_surfacelist = NULL;
3136                 rtlight->static_numshadowtrispvsbytes = 0;
3137                 rtlight->static_shadowtrispvs = NULL;
3138                 rtlight->static_numlighttrispvsbytes = 0;
3139                 rtlight->static_lighttrispvs = NULL;
3140                 rtlight->compiled = false;
3141         }
3142 }
3143
3144 void R_Shadow_UncompileWorldLights(void)
3145 {
3146         size_t lightindex;
3147         dlight_t *light;
3148         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3149         for (lightindex = 0;lightindex < range;lightindex++)
3150         {
3151                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3152                 if (!light)
3153                         continue;
3154                 R_RTLight_Uncompile(&light->rtlight);
3155         }
3156 }
3157
3158 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3159 {
3160         int i, j;
3161         mplane_t plane;
3162         // reset the count of frustum planes
3163         // see rtlight->cached_frustumplanes definition for how much this array
3164         // can hold
3165         rtlight->cached_numfrustumplanes = 0;
3166
3167         if (r_trippy.integer)
3168                 return;
3169
3170         // haven't implemented a culling path for ortho rendering
3171         if (!r_refdef.view.useperspective)
3172         {
3173                 // check if the light is on screen and copy the 4 planes if it is
3174                 for (i = 0;i < 4;i++)
3175                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3176                                 break;
3177                 if (i == 4)
3178                         for (i = 0;i < 4;i++)
3179                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3180                 return;
3181         }
3182
3183 #if 1
3184         // generate a deformed frustum that includes the light origin, this is
3185         // used to cull shadow casting surfaces that can not possibly cast a
3186         // shadow onto the visible light-receiving surfaces, which can be a
3187         // performance gain
3188         //
3189         // if the light origin is onscreen the result will be 4 planes exactly
3190         // if the light origin is offscreen on only one axis the result will
3191         // be exactly 5 planes (split-side case)
3192         // if the light origin is offscreen on two axes the result will be
3193         // exactly 4 planes (stretched corner case)
3194         for (i = 0;i < 4;i++)
3195         {
3196                 // quickly reject standard frustum planes that put the light
3197                 // origin outside the frustum
3198                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3199                         continue;
3200                 // copy the plane
3201                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3202         }
3203         // if all the standard frustum planes were accepted, the light is onscreen
3204         // otherwise we need to generate some more planes below...
3205         if (rtlight->cached_numfrustumplanes < 4)
3206         {
3207                 // at least one of the stock frustum planes failed, so we need to
3208                 // create one or two custom planes to enclose the light origin
3209                 for (i = 0;i < 4;i++)
3210                 {
3211                         // create a plane using the view origin and light origin, and a
3212                         // single point from the frustum corner set
3213                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3214                         VectorNormalize(plane.normal);
3215                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3216                         // see if this plane is backwards and flip it if so
3217                         for (j = 0;j < 4;j++)
3218                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3219                                         break;
3220                         if (j < 4)
3221                         {
3222                                 VectorNegate(plane.normal, plane.normal);
3223                                 plane.dist *= -1;
3224                                 // flipped plane, test again to see if it is now valid
3225                                 for (j = 0;j < 4;j++)
3226                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3227                                                 break;
3228                                 // if the plane is still not valid, then it is dividing the
3229                                 // frustum and has to be rejected
3230                                 if (j < 4)
3231                                         continue;
3232                         }
3233                         // we have created a valid plane, compute extra info
3234                         PlaneClassify(&plane);
3235                         // copy the plane
3236                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3237 #if 1
3238                         // if we've found 5 frustum planes then we have constructed a
3239                         // proper split-side case and do not need to keep searching for
3240                         // planes to enclose the light origin
3241                         if (rtlight->cached_numfrustumplanes == 5)
3242                                 break;
3243 #endif
3244                 }
3245         }
3246 #endif
3247
3248 #if 0
3249         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3250         {
3251                 plane = rtlight->cached_frustumplanes[i];
3252                 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));
3253         }
3254 #endif
3255
3256 #if 0
3257         // now add the light-space box planes if the light box is rotated, as any
3258         // caster outside the oriented light box is irrelevant (even if it passed
3259         // the worldspace light box, which is axial)
3260         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3261         {
3262                 for (i = 0;i < 6;i++)
3263                 {
3264                         vec3_t v;
3265                         VectorClear(v);
3266                         v[i >> 1] = (i & 1) ? -1 : 1;
3267                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3268                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3269                         plane.dist = VectorNormalizeLength(plane.normal);
3270                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3271                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3272                 }
3273         }
3274 #endif
3275
3276 #if 0
3277         // add the world-space reduced box planes
3278         for (i = 0;i < 6;i++)
3279         {
3280                 VectorClear(plane.normal);
3281                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3282                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3283                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3284         }
3285 #endif
3286
3287 #if 0
3288         {
3289         int j, oldnum;
3290         vec3_t points[8];
3291         vec_t bestdist;
3292         // reduce all plane distances to tightly fit the rtlight cull box, which
3293         // is in worldspace
3294         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3295         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3296         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3297         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3298         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3299         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3300         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3301         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3302         oldnum = rtlight->cached_numfrustumplanes;
3303         rtlight->cached_numfrustumplanes = 0;
3304         for (j = 0;j < oldnum;j++)
3305         {
3306                 // find the nearest point on the box to this plane
3307                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3308                 for (i = 1;i < 8;i++)
3309                 {
3310                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3311                         if (bestdist > dist)
3312                                 bestdist = dist;
3313                 }
3314                 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);
3315                 // if the nearest point is near or behind the plane, we want this
3316                 // plane, otherwise the plane is useless as it won't cull anything
3317                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3318                 {
3319                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3320                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3321                 }
3322         }
3323         }
3324 #endif
3325 }
3326
3327 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3328 {
3329         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3330
3331         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3332         {
3333                 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3334                 if (mesh->sidetotals[r_shadow_shadowmapside])
3335                 {
3336                         CHECKGLERROR
3337                         GL_CullFace(GL_NONE);
3338                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3339                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3340                         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);
3341                         CHECKGLERROR
3342                 }
3343         }
3344         else if (r_refdef.scene.worldentity->model)
3345                 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);
3346
3347         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3348 }
3349
3350 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3351 {
3352         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3353         vec_t relativeshadowradius;
3354         RSurf_ActiveModelEntity(ent, false, false, false);
3355         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3356         // we need to re-init the shader for each entity because the matrix changed
3357         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3358         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3359         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3360         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3361         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3362         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3363         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3364         ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3365         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3366 }
3367
3368 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3369 {
3370         // set up properties for rendering light onto this entity
3371         RSurf_ActiveModelEntity(ent, true, true, false);
3372         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3373         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3374         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3375         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3376 }
3377
3378 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3379 {
3380         if (!r_refdef.scene.worldmodel->DrawLight)
3381                 return;
3382
3383         // set up properties for rendering light onto this entity
3384         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3385         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3386         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3387         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3388         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3389
3390         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3391
3392         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3393 }
3394
3395 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3396 {
3397         dp_model_t *model = ent->model;
3398         if (!model->DrawLight)
3399                 return;
3400
3401         R_Shadow_SetupEntityLight(ent);
3402
3403         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3404
3405         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3406 }
3407
3408 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3409 {
3410         int i;
3411         float f;
3412         int numleafs, numsurfaces;
3413         int *leaflist, *surfacelist;
3414         unsigned char *leafpvs;
3415         unsigned char *shadowtrispvs;
3416         unsigned char *lighttrispvs;
3417         //unsigned char *surfacesides;
3418         int numlightentities;
3419         int numlightentities_noselfshadow;
3420         int numshadowentities;
3421         int numshadowentities_noselfshadow;
3422         // FIXME: bounds check lightentities and shadowentities, etc.
3423         static entity_render_t *lightentities[MAX_EDICTS];
3424         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3425         static entity_render_t *shadowentities[MAX_EDICTS];
3426         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3427         qboolean nolight;
3428         qboolean castshadows;
3429
3430         rtlight->draw = false;
3431         rtlight->cached_numlightentities = 0;
3432         rtlight->cached_numlightentities_noselfshadow = 0;
3433         rtlight->cached_numshadowentities = 0;
3434         rtlight->cached_numshadowentities_noselfshadow = 0;
3435         rtlight->cached_numsurfaces = 0;
3436         rtlight->cached_lightentities = NULL;
3437         rtlight->cached_lightentities_noselfshadow = NULL;
3438         rtlight->cached_shadowentities = NULL;
3439         rtlight->cached_shadowentities_noselfshadow = NULL;
3440         rtlight->cached_shadowtrispvs = NULL;
3441         rtlight->cached_lighttrispvs = NULL;
3442         rtlight->cached_surfacelist = NULL;
3443         rtlight->shadowmapsidesize = 0;
3444
3445         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3446         // skip lights that are basically invisible (color 0 0 0)
3447         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3448
3449         // loading is done before visibility checks because loading should happen
3450         // all at once at the start of a level, not when it stalls gameplay.
3451         // (especially important to benchmarks)
3452         // compile light
3453         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3454         {
3455                 if (rtlight->compiled)
3456                         R_RTLight_Uncompile(rtlight);
3457                 R_RTLight_Compile(rtlight);
3458         }
3459
3460         // load cubemap
3461         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3462
3463         // look up the light style value at this time
3464         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3465         VectorScale(rtlight->color, f, rtlight->currentcolor);
3466         /*
3467         if (rtlight->selected)
3468         {
3469                 f = 2 + sin(realtime * M_PI * 4.0);
3470                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3471         }
3472         */
3473
3474         // skip if lightstyle is currently off
3475         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3476                 return;
3477
3478         // skip processing on corona-only lights
3479         if (nolight)
3480                 return;
3481
3482         // skip if the light box is not touching any visible leafs
3483         if (r_shadow_culllights_pvs.integer
3484                 && r_refdef.scene.worldmodel
3485                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3486                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3487                 return;
3488
3489         // skip if the light box is not visible to traceline
3490         if (r_shadow_culllights_trace.integer)
3491         {
3492                 if (rtlight->trace_timer != realtime && R_CanSeeBox(rtlight->trace_timer == 0 ? r_shadow_culllights_trace_tempsamples.integer : r_shadow_culllights_trace_samples.integer, r_shadow_culllights_trace_eyejitter.value, r_shadow_culllights_trace_enlarge.value, r_shadow_culllights_trace_expand.value, r_shadow_culllights_trace_pad.value, r_refdef.view.origin, rtlight->cullmins, rtlight->cullmaxs))
3493                         rtlight->trace_timer = realtime;
3494                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3495                         return;
3496         }
3497
3498         // skip if the light box is off screen
3499         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3500                 return;
3501
3502         // in the typical case this will be quickly replaced by GetLightInfo
3503         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3504         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3505
3506         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3507
3508         // 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
3509         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3510                 return;
3511
3512         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3513         {
3514                 // compiled light, world available and can receive realtime lighting
3515                 // retrieve leaf information
3516                 numleafs = rtlight->static_numleafs;
3517                 leaflist = rtlight->static_leaflist;
3518                 leafpvs = rtlight->static_leafpvs;
3519                 numsurfaces = rtlight->static_numsurfaces;
3520                 surfacelist = rtlight->static_surfacelist;
3521                 //surfacesides = NULL;
3522                 shadowtrispvs = rtlight->static_shadowtrispvs;
3523                 lighttrispvs = rtlight->static_lighttrispvs;
3524         }
3525         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3526         {
3527                 // dynamic light, world available and can receive realtime lighting
3528                 // calculate lit surfaces and leafs
3529                 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);
3530                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3531                 leaflist = r_shadow_buffer_leaflist;
3532                 leafpvs = r_shadow_buffer_leafpvs;
3533                 surfacelist = r_shadow_buffer_surfacelist;
3534                 //surfacesides = r_shadow_buffer_surfacesides;
3535                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3536                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3537                 // if the reduced leaf bounds are offscreen, skip it
3538                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3539                         return;
3540         }
3541         else
3542         {
3543                 // no world
3544                 numleafs = 0;
3545                 leaflist = NULL;
3546                 leafpvs = NULL;
3547                 numsurfaces = 0;
3548                 surfacelist = NULL;
3549                 //surfacesides = NULL;
3550                 shadowtrispvs = NULL;
3551                 lighttrispvs = NULL;
3552         }
3553         // check if light is illuminating any visible leafs
3554         if (numleafs)
3555         {
3556                 for (i = 0; i < numleafs; i++)
3557                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3558                                 break;
3559                 if (i == numleafs)
3560                         return;
3561         }
3562
3563         // make a list of lit entities and shadow casting entities
3564         numlightentities = 0;
3565         numlightentities_noselfshadow = 0;
3566         numshadowentities = 0;
3567         numshadowentities_noselfshadow = 0;
3568
3569         // add dynamic entities that are lit by the light
3570         for (i = 0; i < r_refdef.scene.numentities; i++)
3571         {
3572                 dp_model_t *model;
3573                 entity_render_t *ent = r_refdef.scene.entities[i];
3574                 vec3_t org;
3575                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3576                         continue;
3577                 // skip the object entirely if it is not within the valid
3578                 // shadow-casting region (which includes the lit region)
3579                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3580                         continue;
3581                 if (!(model = ent->model))
3582                         continue;
3583                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3584                 {
3585                         // this entity wants to receive light, is visible, and is
3586                         // inside the light box
3587                         // TODO: check if the surfaces in the model can receive light
3588                         // so now check if it's in a leaf seen by the light
3589                         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))
3590                                 continue;
3591                         if (ent->flags & RENDER_NOSELFSHADOW)
3592                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3593                         else
3594                                 lightentities[numlightentities++] = ent;
3595                         // since it is lit, it probably also casts a shadow...
3596                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3597                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3598                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3599                         {
3600                                 // note: exterior models without the RENDER_NOSELFSHADOW
3601                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3602                                 // are lit normally, this means that they are
3603                                 // self-shadowing but do not shadow other
3604                                 // RENDER_NOSELFSHADOW entities such as the gun
3605                                 // (very weird, but keeps the player shadow off the gun)
3606                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3607                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3608                                 else
3609                                         shadowentities[numshadowentities++] = ent;
3610                         }
3611                 }
3612                 else if (ent->flags & RENDER_SHADOW)
3613                 {
3614                         // this entity is not receiving light, but may still need to
3615                         // cast a shadow...
3616                         // TODO: check if the surfaces in the model can cast shadow
3617                         // now check if it is in a leaf seen by the light
3618                         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))
3619                                 continue;
3620                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3621                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3622                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3623                         {
3624                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3625                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3626                                 else
3627                                         shadowentities[numshadowentities++] = ent;
3628                         }
3629                 }
3630         }
3631
3632         // return if there's nothing at all to light
3633         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3634                 return;
3635
3636         // count this light in the r_speeds
3637         r_refdef.stats[r_stat_lights]++;
3638
3639         // flag it as worth drawing later
3640         rtlight->draw = true;
3641
3642         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3643         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3644         if (!castshadows)
3645                 numshadowentities = numshadowentities_noselfshadow = 0;
3646         rtlight->castshadows = castshadows;
3647
3648         // cache all the animated entities that cast a shadow but are not visible
3649         for (i = 0; i < numshadowentities; i++)
3650                 R_AnimCache_GetEntity(shadowentities[i], false, false);
3651         for (i = 0; i < numshadowentities_noselfshadow; i++)
3652                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3653
3654         // 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)
3655         if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3656         {
3657                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3658                         shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3659                 numshadowentities_noselfshadow = 0;
3660         }
3661
3662         // we can convert noselfshadow to regular if there are no casters of that type
3663         if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3664         {
3665                 for (i = 0; i < numlightentities_noselfshadow; i++)
3666                         lightentities[numlightentities++] = lightentities_noselfshadow[i];
3667                 numlightentities_noselfshadow = 0;
3668         }
3669
3670         // allocate some temporary memory for rendering this light later in the frame
3671         // reusable buffers need to be copied, static data can be used as-is
3672         rtlight->cached_numlightentities               = numlightentities;
3673         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3674         rtlight->cached_numshadowentities              = numshadowentities;
3675         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3676         rtlight->cached_numsurfaces                    = numsurfaces;
3677         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3678         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3679         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3680         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3681         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3682         {
3683                 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3684                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3685                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3686                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3687                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3688         }
3689         else
3690         {
3691                 // compiled light data
3692                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3693                 rtlight->cached_lighttrispvs = lighttrispvs;
3694                 rtlight->cached_surfacelist = surfacelist;
3695         }
3696
3697         if (R_Shadow_ShadowMappingEnabled())
3698         {
3699                 // figure out the shadowmapping parameters for this light
3700                 vec3_t nearestpoint;
3701                 vec_t distance;
3702                 int lodlinear;
3703                 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3704                 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3705                 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3706                 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3707                 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3708                 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3709                 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3710                 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3711                 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3712         }
3713 }
3714
3715 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3716 {
3717         int i;
3718         int numsurfaces;
3719         unsigned char *shadowtrispvs, *surfacesides;
3720         int numlightentities;
3721         int numlightentities_noselfshadow;
3722         int numshadowentities;
3723         int numshadowentities_noselfshadow;
3724         entity_render_t **lightentities;
3725         entity_render_t **lightentities_noselfshadow;
3726         entity_render_t **shadowentities;
3727         entity_render_t **shadowentities_noselfshadow;
3728         int *surfacelist;
3729         static unsigned char entitysides[MAX_EDICTS];
3730         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3731         float borderbias;
3732         int side;
3733         int size;
3734         int castermask;
3735         int receivermask;
3736         matrix4x4_t radiustolight;
3737
3738         // check if we cached this light this frame (meaning it is worth drawing)
3739         if (!rtlight->draw || !rtlight->castshadows)
3740                 return;
3741
3742         // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3743         if (rtlight->shadowmapatlassidesize == 0)
3744         {
3745                 rtlight->castshadows = false;
3746                 return;
3747         }
3748
3749         // set up a scissor rectangle for this light
3750         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3751                 return;
3752
3753         // don't let sound skip if going slow
3754         if (r_refdef.scene.extraupdate)
3755                 S_ExtraUpdate();
3756
3757         numlightentities = rtlight->cached_numlightentities;
3758         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3759         numshadowentities = rtlight->cached_numshadowentities;
3760         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3761         numsurfaces = rtlight->cached_numsurfaces;
3762         lightentities = rtlight->cached_lightentities;
3763         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3764         shadowentities = rtlight->cached_shadowentities;
3765         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3766         shadowtrispvs = rtlight->cached_shadowtrispvs;
3767         surfacelist = rtlight->cached_surfacelist;
3768
3769         // make this the active rtlight for rendering purposes
3770         R_Shadow_RenderMode_ActiveLight(rtlight);
3771
3772         radiustolight = rtlight->matrix_worldtolight;
3773         Matrix4x4_Abs(&radiustolight);
3774
3775         size = rtlight->shadowmapatlassidesize;
3776         borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3777
3778         surfacesides = NULL;
3779         castermask = 0;
3780         receivermask = 0;
3781         if (numsurfaces)
3782         {
3783                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3784                 {
3785                         castermask = rtlight->static_shadowmap_casters;
3786                         receivermask = rtlight->static_shadowmap_receivers;
3787                 }
3788                 else
3789                 {
3790                         surfacesides = r_shadow_buffer_surfacesides;
3791                         for (i = 0; i < numsurfaces; i++)
3792                         {
3793                                 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3794                                 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3795                                 castermask |= surfacesides[i];
3796                                 receivermask |= surfacesides[i];
3797                         }
3798                 }
3799         }
3800
3801         for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3802                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3803         for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3804                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3805
3806         receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3807
3808         if (receivermask)
3809         {
3810                 for (i = 0; i < numshadowentities; i++)
3811                         castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3812                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3813                         castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3814         }
3815
3816         // there is no need to render shadows for sides that have no receivers...
3817         castermask &= receivermask;
3818
3819         //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3820
3821         // render shadow casters into shadowmaps for this light
3822         for (side = 0; side < 6; side++)
3823         {
3824                 int bit = 1 << side;
3825                 if (castermask & bit)
3826                 {
3827                         R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3828                         if (numsurfaces)
3829                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3830                         for (i = 0; i < numshadowentities; i++)
3831                                 if (entitysides[i] & bit)
3832                                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3833                         for (i = 0; i < numshadowentities_noselfshadow; i++)
3834                                 if (entitysides_noselfshadow[i] & bit)
3835                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3836                 }
3837         }
3838         // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3839         if (numshadowentities_noselfshadow)
3840         {
3841                 for (side = 0; side < 6; side++)
3842                 {
3843                         int bit = 1 << side;
3844                         if (castermask & bit)
3845                         {
3846                                 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3847                                 if (numsurfaces)
3848                                         R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3849                                 for (i = 0; i < numshadowentities; i++)
3850                                         if (entitysides[i] & bit)
3851                                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3852                         }
3853                 }
3854         }
3855 }
3856
3857 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3858 {
3859         int i;
3860         int numsurfaces;
3861         unsigned char *lighttrispvs;
3862         int numlightentities;
3863         int numlightentities_noselfshadow;
3864         entity_render_t **lightentities;
3865         entity_render_t **lightentities_noselfshadow;
3866         entity_render_t **shadowentities;
3867         entity_render_t **shadowentities_noselfshadow;
3868         int *surfacelist;
3869         qboolean castshadows;
3870
3871         // check if we cached this light this frame (meaning it is worth drawing)
3872         if (!rtlight->draw)
3873                 return;
3874
3875         // set up a scissor rectangle for this light
3876         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3877                 return;
3878
3879         // don't let sound skip if going slow
3880         if (r_refdef.scene.extraupdate)
3881                 S_ExtraUpdate();
3882
3883         numlightentities = rtlight->cached_numlightentities;
3884         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3885         numsurfaces = rtlight->cached_numsurfaces;
3886         lightentities = rtlight->cached_lightentities;
3887         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3888         shadowentities = rtlight->cached_shadowentities;
3889         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3890         lighttrispvs = rtlight->cached_lighttrispvs;
3891         surfacelist = rtlight->cached_surfacelist;
3892         castshadows = rtlight->castshadows;
3893
3894         // make this the active rtlight for rendering purposes
3895         R_Shadow_RenderMode_ActiveLight(rtlight);
3896
3897         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3898         {
3899                 // optionally draw the illuminated areas
3900                 // for performance analysis by level designers
3901                 R_Shadow_RenderMode_VisibleLighting(false);
3902                 if (numsurfaces)
3903                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3904                 for (i = 0;i < numlightentities;i++)
3905                         R_Shadow_DrawEntityLight(lightentities[i]);
3906                 for (i = 0;i < numlightentities_noselfshadow;i++)
3907                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3908         }
3909
3910         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3911         {
3912                 float borderbias;
3913                 int size;
3914                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3915                 Matrix4x4_Abs(&radiustolight);
3916
3917                 size = rtlight->shadowmapatlassidesize;
3918                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3919
3920                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3921
3922                 // render lighting using the depth texture as shadowmap
3923                 // draw lighting in the unmasked areas
3924                 if (numsurfaces + numlightentities)
3925                 {
3926                         R_Shadow_RenderMode_Lighting(false, true, false);
3927                         // draw lighting in the unmasked areas
3928                         if (numsurfaces)
3929                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3930                         for (i = 0; i < numlightentities; i++)
3931                                 R_Shadow_DrawEntityLight(lightentities[i]);
3932                 }
3933                 // offset to the noselfshadow part of the atlas and draw those too
3934                 if (numlightentities_noselfshadow)
3935                 {
3936                         R_Shadow_RenderMode_Lighting(false, true, true);
3937                         for (i = 0; i < numlightentities_noselfshadow; i++)
3938                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3939                 }
3940
3941                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3942                 if (r_shadow_usingdeferredprepass)
3943                         R_Shadow_RenderMode_DrawDeferredLight(true);
3944         }
3945         else
3946         {
3947                 // draw lighting in the unmasked areas
3948                 R_Shadow_RenderMode_Lighting(false, false, false);
3949                 if (numsurfaces)
3950                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3951                 for (i = 0;i < numlightentities;i++)
3952                         R_Shadow_DrawEntityLight(lightentities[i]);
3953                 for (i = 0;i < numlightentities_noselfshadow;i++)
3954                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3955
3956                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3957                 if (r_shadow_usingdeferredprepass)
3958                         R_Shadow_RenderMode_DrawDeferredLight(false);
3959         }
3960 }
3961
3962 static void R_Shadow_FreeDeferred(void)
3963 {
3964         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3965         r_shadow_prepassgeometryfbo = 0;
3966
3967         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3968         r_shadow_prepasslightingdiffusespecularfbo = 0;
3969
3970         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3971         r_shadow_prepasslightingdiffusefbo = 0;
3972
3973         if (r_shadow_prepassgeometrydepthbuffer)
3974                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3975         r_shadow_prepassgeometrydepthbuffer = NULL;
3976
3977         if (r_shadow_prepassgeometrynormalmaptexture)
3978                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3979         r_shadow_prepassgeometrynormalmaptexture = NULL;
3980
3981         if (r_shadow_prepasslightingdiffusetexture)
3982                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3983         r_shadow_prepasslightingdiffusetexture = NULL;
3984
3985         if (r_shadow_prepasslightingspeculartexture)
3986                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3987         r_shadow_prepasslightingspeculartexture = NULL;
3988 }
3989
3990 void R_Shadow_DrawPrepass(void)
3991 {
3992         int i;
3993         int lnum;
3994         entity_render_t *ent;
3995         float clearcolor[4];
3996
3997         R_Mesh_ResetTextureState();
3998         GL_DepthMask(true);
3999         GL_ColorMask(1,1,1,1);
4000         GL_BlendFunc(GL_ONE, GL_ZERO);
4001         GL_Color(1,1,1,1);
4002         GL_DepthTest(true);
4003         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4004         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4005         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4006         if (r_timereport_active)
4007                 R_TimeReport("prepasscleargeom");
4008
4009         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4010                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4011         if (r_timereport_active)
4012                 R_TimeReport("prepassworld");
4013
4014         for (i = 0;i < r_refdef.scene.numentities;i++)
4015         {
4016                 if (!r_refdef.viewcache.entityvisible[i])
4017                         continue;
4018                 ent = r_refdef.scene.entities[i];
4019                 if (ent->model && ent->model->DrawPrepass != NULL)
4020                         ent->model->DrawPrepass(ent);
4021         }
4022
4023         if (r_timereport_active)
4024                 R_TimeReport("prepassmodels");
4025
4026         GL_DepthMask(false);
4027         GL_ColorMask(1,1,1,1);
4028         GL_Color(1,1,1,1);
4029         GL_DepthTest(true);
4030         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4031         Vector4Set(clearcolor, 0, 0, 0, 0);
4032         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4033         if (r_timereport_active)
4034                 R_TimeReport("prepassclearlit");
4035
4036         R_Shadow_RenderMode_Begin();
4037
4038         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4039                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4040
4041         R_Shadow_RenderMode_End();
4042
4043         if (r_timereport_active)
4044                 R_TimeReport("prepasslights");
4045 }
4046
4047 #define MAX_SCENELIGHTS 65536
4048 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4049 {
4050         if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4051         {
4052                 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4053                         return false;
4054                 r_shadow_scenemaxlights *= 2;
4055                 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4056                 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4057         }
4058         r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4059         return true;
4060 }
4061
4062 void R_Shadow_DrawLightSprites(void);
4063 void R_Shadow_PrepareLights(void)
4064 {
4065         int flag;
4066         int lnum;
4067         size_t lightindex;
4068         dlight_t *light;
4069         size_t range;
4070         float f;
4071
4072         int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4073         int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4074         int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4075
4076         if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4077                 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4078                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4079                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4080                 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4081                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4082                 r_shadow_shadowmapborder != shadowmapborder ||
4083                 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4084                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4085                 R_Shadow_FreeShadowMaps();
4086
4087         r_shadow_usingshadowmaportho = false;
4088
4089         switch (vid.renderpath)
4090         {
4091         case RENDERPATH_GL32:
4092 #ifndef USE_GLES2
4093                 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4094                 {
4095                         r_shadow_usingdeferredprepass = false;
4096                         if (r_shadow_prepass_width)
4097                                 R_Shadow_FreeDeferred();
4098                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4099                         break;
4100                 }
4101
4102                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4103                 {
4104                         R_Shadow_FreeDeferred();
4105
4106                         r_shadow_usingdeferredprepass = true;
4107                         r_shadow_prepass_width = vid.width;
4108                         r_shadow_prepass_height = vid.height;
4109                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4110                         r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4111                         r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4112                         r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4113
4114                         // set up the geometry pass fbo (depth + normalmap)
4115                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4116                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4117                         // render depth into a renderbuffer and other important properties into the normalmap texture
4118
4119                         // set up the lighting pass fbo (diffuse + specular)
4120                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4121                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4122                         // render diffuse into one texture and specular into another,
4123                         // with depth and normalmap bound as textures,
4124                         // with depth bound as attachment as well
4125
4126                         // set up the lighting pass fbo (diffuse)
4127                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4128                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4129                         // render diffuse into one texture,
4130                         // with depth and normalmap bound as textures,
4131                         // with depth bound as attachment as well
4132                 }
4133 #endif
4134                 break;
4135         case RENDERPATH_GLES2:
4136                 r_shadow_usingdeferredprepass = false;
4137                 break;
4138         }
4139
4140         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);
4141
4142         r_shadow_scenenumlights = 0;
4143         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4144         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4145         for (lightindex = 0; lightindex < range; lightindex++)
4146         {
4147                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4148                 if (light && (light->flags & flag))
4149                 {
4150                         R_Shadow_PrepareLight(&light->rtlight);
4151                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4152                 }
4153         }
4154         if (r_refdef.scene.rtdlight)
4155         {
4156                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4157                 {
4158                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4159                         R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4160                 }
4161         }
4162         else if (gl_flashblend.integer)
4163         {
4164                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4165                 {
4166                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4167                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4168                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4169                 }
4170         }
4171
4172         // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4173         if (r_shadow_debuglight.integer >= 0)
4174         {
4175                 r_shadow_scenenumlights = 0;
4176                 lightindex = r_shadow_debuglight.integer;
4177                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4178                 if (light)
4179                 {
4180                         R_Shadow_PrepareLight(&light->rtlight);
4181                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4182                 }
4183         }
4184
4185         // if we're doing shadowmaps we need to prepare the atlas layout now
4186         if (R_Shadow_ShadowMappingEnabled())
4187         {
4188                 int lod;
4189
4190                 // allocate shadowmaps in the atlas now
4191                 // 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...
4192                 for (lod = 0; lod < 16; lod++)
4193                 {
4194                         int packing_success = 0;
4195                         int packing_failure = 0;
4196                         Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4197                         // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4198                         if (r_shadow_shadowmapatlas_modelshadows_size)
4199                                 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);
4200                         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4201                         {
4202                                 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4203                                 int size = rtlight->shadowmapsidesize >> lod;
4204                                 int width, height;
4205                                 if (!rtlight->castshadows)
4206                                         continue;
4207                                 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4208                                 width = size * 2;
4209                                 height = size * 3;
4210                                 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4211                                 if (rtlight->cached_numshadowentities_noselfshadow)
4212                                         width *= 2;
4213                                 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4214                                 {
4215                                         rtlight->shadowmapatlassidesize = size;
4216                                         packing_success++;
4217                                 }
4218                                 else
4219                                 {
4220                                         // note down that we failed to pack this one, it will have to disable shadows
4221                                         rtlight->shadowmapatlassidesize = 0;
4222                                         packing_failure++;
4223                                 }
4224                         }
4225                         // generally everything fits and we stop here on the first iteration
4226                         if (packing_failure == 0)
4227                                 break;
4228                 }
4229         }
4230
4231         if (r_editlights.integer)
4232                 R_Shadow_DrawLightSprites();
4233 }
4234
4235 void R_Shadow_DrawShadowMaps(void)
4236 {
4237         R_Shadow_RenderMode_Begin();
4238         R_Shadow_RenderMode_ActiveLight(NULL);
4239
4240         // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4241         R_Shadow_ClearShadowMapTexture();
4242
4243         // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4244         if (r_shadow_shadowmapatlas_modelshadows_size)
4245         {
4246                 R_Shadow_DrawModelShadowMaps();
4247                 // don't let sound skip if going slow
4248                 if (r_refdef.scene.extraupdate)
4249                         S_ExtraUpdate();
4250         }
4251
4252         if (R_Shadow_ShadowMappingEnabled())
4253         {
4254                 int lnum;
4255                 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4256                         R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4257         }
4258
4259         R_Shadow_RenderMode_End();
4260 }
4261
4262 void R_Shadow_DrawLights(void)
4263 {
4264         int lnum;
4265
4266         R_Shadow_RenderMode_Begin();
4267
4268         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4269                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4270
4271         R_Shadow_RenderMode_End();
4272 }
4273
4274 #define MAX_MODELSHADOWS 1024
4275 static int r_shadow_nummodelshadows;
4276 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4277
4278 void R_Shadow_PrepareModelShadows(void)
4279 {
4280         int i;
4281         float scale, size, radius, dot1, dot2;
4282         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4283         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4284         entity_render_t *ent;
4285
4286         r_shadow_nummodelshadows = 0;
4287         r_shadow_shadowmapatlas_modelshadows_size = 0;
4288
4289         if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4290                 return;
4291
4292         size = r_shadow_shadowmaptexturesize / 4;
4293         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4294         radius = 0.5f * size / scale;
4295
4296         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4297         VectorCopy(prvmshadowdir, shadowdir);
4298         VectorNormalize(shadowdir);
4299         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4300         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4301         if (fabs(dot1) <= fabs(dot2))
4302                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4303         else
4304                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4305         VectorNormalize(shadowforward);
4306         CrossProduct(shadowdir, shadowforward, shadowright);
4307         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4308         VectorCopy(prvmshadowfocus, shadowfocus);
4309         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4310         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4311         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4312         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4313         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4314                 dot1 = 1;
4315         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4316
4317         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4318         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4319         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4320         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4321         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4322         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4323
4324         for (i = 0; i < r_refdef.scene.numentities; i++)
4325         {
4326                 ent = r_refdef.scene.entities[i];
4327                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4328                         continue;
4329                 // cast shadows from anything of the map (submodels are optional)
4330                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4331                 {
4332                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4333                                 break;
4334                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4335                         R_AnimCache_GetEntity(ent, false, false);
4336                 }
4337         }
4338
4339         if (r_shadow_nummodelshadows)
4340         {
4341                 r_shadow_shadowmapatlas_modelshadows_x = 0;
4342                 r_shadow_shadowmapatlas_modelshadows_y = 0;
4343                 r_shadow_shadowmapatlas_modelshadows_size = size;
4344         }
4345 }
4346
4347 static void R_Shadow_DrawModelShadowMaps(void)
4348 {
4349         int i;
4350         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4351         entity_render_t *ent;
4352         vec3_t relativelightorigin;
4353         vec3_t relativelightdirection, relativeforward, relativeright;
4354         vec3_t relativeshadowmins, relativeshadowmaxs;
4355         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4356         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4357         float m[12];
4358         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4359         r_viewport_t viewport;
4360
4361         size = r_shadow_shadowmapatlas_modelshadows_size;
4362         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4363         radius = 0.5f / scale;
4364         nearclip = -r_shadows_throwdistance.value;
4365         farclip = r_shadows_throwdistance.value;
4366         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);
4367
4368         // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4369         r_shadow_modelshadowmap_parameters[0] = size;
4370         r_shadow_modelshadowmap_parameters[1] = size;
4371         r_shadow_modelshadowmap_parameters[2] = 1.0;
4372         r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4373         r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4374         r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4375         r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4376         r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4377         r_shadow_usingshadowmaportho = true;
4378
4379         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4380         VectorCopy(prvmshadowdir, shadowdir);
4381         VectorNormalize(shadowdir);
4382         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4383         VectorCopy(prvmshadowfocus, shadowfocus);
4384         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4385         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4386         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4387         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4388         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4389         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4390         if (fabs(dot1) <= fabs(dot2))
4391                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4392         else
4393                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4394         VectorNormalize(shadowforward);
4395         VectorM(scale, shadowforward, &m[0]);
4396         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4397                 dot1 = 1;
4398         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4399         CrossProduct(shadowdir, shadowforward, shadowright);
4400         VectorM(scale, shadowright, &m[4]);
4401         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4402         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4403         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4404         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4405         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4406         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);
4407         R_SetViewport(&viewport);
4408
4409         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4410
4411         // render into a slightly restricted region so that the borders of the
4412         // shadowmap area fade away, rather than streaking across everything
4413         // outside the usable area
4414         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4415
4416         for (i = 0;i < r_shadow_nummodelshadows;i++)
4417         {
4418                 ent = r_shadow_modelshadows[i];
4419                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4420                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4421                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4422                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4423                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4424                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4425                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4426                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4427                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4428                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4429                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4430                 RSurf_ActiveModelEntity(ent, false, false, false);
4431                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4432                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4433         }
4434
4435 #if 0
4436         if (r_test.integer)
4437         {
4438                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4439                 CHECKGLERROR
4440                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4441                 CHECKGLERROR
4442                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4443                 Cvar_SetValueQuick(&r_test, 0);
4444                 Z_Free(rawpixels);
4445         }
4446 #endif
4447
4448         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4449         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4450         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4451         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4452         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4453         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4454 }
4455
4456 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4457 {
4458         float zdist;
4459         vec3_t centerorigin;
4460 #ifndef USE_GLES2
4461         float vertex3f[12];
4462 #endif
4463         // if it's too close, skip it
4464         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4465                 return;
4466         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4467         if (zdist < 32)
4468                 return;
4469         if (usequery && r_numqueries + 2 <= r_maxqueries)
4470         {
4471                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4472                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4473                 // 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
4474                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4475
4476                 switch(vid.renderpath)
4477                 {
4478                 case RENDERPATH_GL32:
4479                 case RENDERPATH_GLES2:
4480 #ifndef USE_GLES2
4481                         CHECKGLERROR
4482                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4483                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4484                         GL_DepthFunc(GL_ALWAYS);
4485                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4486                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4487                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4488                         qglEndQuery(GL_SAMPLES_PASSED);
4489                         GL_DepthFunc(GL_LEQUAL);
4490                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4491                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4492                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4493                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4494                         qglEndQuery(GL_SAMPLES_PASSED);
4495                         CHECKGLERROR
4496 #endif
4497                         break;
4498                 }
4499         }
4500         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4501 }
4502
4503 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4504
4505 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4506 {
4507         vec3_t color;
4508         unsigned int occlude = 0;
4509
4510         // now we have to check the query result
4511         if (rtlight->corona_queryindex_visiblepixels)
4512         {
4513                 switch(vid.renderpath)
4514                 {
4515                 case RENDERPATH_GL32:
4516                 case RENDERPATH_GLES2:
4517 #ifndef USE_GLES2
4518                         // store the pixel counts into a uniform buffer for the shader to
4519                         // use - we'll never know the results on the cpu without
4520                         // synchronizing and we don't want that
4521 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
4522                         if (!r_shadow_occlusion_buf) {
4523                                 qglGenBuffers(1, &r_shadow_occlusion_buf);
4524                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4525                                 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4526                         } else {
4527                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4528                         }
4529                         qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4530                         qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4531                         qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4532                         occlude = MATERIALFLAG_OCCLUDE;
4533                         cscale *= rtlight->corona_visibility;
4534                         CHECKGLERROR
4535                         break;
4536 #else
4537                         return;
4538 #endif
4539                 }
4540         }
4541         else
4542         {
4543                 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4544                         return;
4545         }
4546         VectorScale(rtlight->currentcolor, cscale, color);
4547         if (VectorLength(color) > (1.0f / 256.0f))
4548         {
4549                 float vertex3f[12];
4550                 qboolean negated = (color[0] + color[1] + color[2] < 0);
4551                 if(negated)
4552                 {
4553                         VectorNegate(color, color);
4554                         GL_BlendEquationSubtract(true);
4555                 }
4556                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4557                 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);
4558                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4559                 if(negated)
4560                         GL_BlendEquationSubtract(false);
4561         }
4562 }
4563
4564 void R_Shadow_DrawCoronas(void)
4565 {
4566         int i, flag;
4567         qboolean usequery = false;
4568         size_t lightindex;
4569         dlight_t *light;
4570         rtlight_t *rtlight;
4571         size_t range;
4572         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4573                 return;
4574         if (r_fb.water.renderingscene)
4575                 return;
4576         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4577         R_EntityMatrix(&identitymatrix);
4578
4579         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4580
4581         // check occlusion of coronas, using occlusion queries or raytraces
4582         r_numqueries = 0;
4583         switch (vid.renderpath)
4584         {
4585         case RENDERPATH_GL32:
4586         case RENDERPATH_GLES2:
4587                 usequery = r_coronas_occlusionquery.integer;
4588 #ifndef USE_GLES2
4589                 if (usequery)
4590                 {
4591                         GL_ColorMask(0,0,0,0);
4592                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4593                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4594                         {
4595                                 i = r_maxqueries;
4596                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4597                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4598                                 CHECKGLERROR
4599                                 qglGenQueries(r_maxqueries - i, r_queries + i);
4600                                 CHECKGLERROR
4601                         }
4602                         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4603                         GL_BlendFunc(GL_ONE, GL_ZERO);
4604                         GL_CullFace(GL_NONE);
4605                         GL_DepthMask(false);
4606                         GL_DepthRange(0, 1);
4607                         GL_PolygonOffset(0, 0);
4608                         GL_DepthTest(true);
4609                         R_Mesh_ResetTextureState();
4610                         R_SetupShader_Generic_NoTexture(false, false);
4611                 }
4612 #endif
4613                 break;
4614         }
4615         for (lightindex = 0;lightindex < range;lightindex++)
4616         {
4617                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4618                 if (!light)
4619                         continue;
4620                 rtlight = &light->rtlight;
4621                 rtlight->corona_visibility = 0;
4622                 rtlight->corona_queryindex_visiblepixels = 0;
4623                 rtlight->corona_queryindex_allpixels = 0;
4624                 if (!(rtlight->flags & flag))
4625                         continue;
4626                 if (rtlight->corona <= 0)
4627                         continue;
4628                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4629                         continue;
4630                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4631         }
4632         for (i = 0;i < r_refdef.scene.numlights;i++)
4633         {
4634                 rtlight = r_refdef.scene.lights[i];
4635                 rtlight->corona_visibility = 0;
4636                 rtlight->corona_queryindex_visiblepixels = 0;
4637                 rtlight->corona_queryindex_allpixels = 0;
4638                 if (!(rtlight->flags & flag))
4639                         continue;
4640                 if (rtlight->corona <= 0)
4641                         continue;
4642                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4643         }
4644         if (usequery)
4645                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4646
4647         // now draw the coronas using the query data for intensity info
4648         for (lightindex = 0;lightindex < range;lightindex++)
4649         {
4650                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4651                 if (!light)
4652                         continue;
4653                 rtlight = &light->rtlight;
4654                 if (rtlight->corona_visibility <= 0)
4655                         continue;
4656                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4657         }
4658         for (i = 0;i < r_refdef.scene.numlights;i++)
4659         {
4660                 rtlight = r_refdef.scene.lights[i];
4661                 if (rtlight->corona_visibility <= 0)
4662                         continue;
4663                 if (gl_flashblend.integer)
4664                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4665                 else
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_client);
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(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6026         Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6027         Cmd_AddCommand(&cmd_client, "r_editlights_reload", R_Shadow_EditLights_Reload_f, "reloads rtlights file (or imports from .lights file or .ent file or the map itself)");
6028         Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6029         Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6030         Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6031         Cmd_AddCommand(&cmd_client, "r_editlights_editall", R_Shadow_EditLights_EditAll_f, "changes a property on ALL lights at once (tip: use radiusscale and colorscale to alter these properties)");
6032         Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6033         Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6034         Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6035         Cmd_AddCommand(&cmd_client, "r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6036         Cmd_AddCommand(&cmd_client, "r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6037         Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6038         Cmd_AddCommand(&cmd_client, "r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6039         Cmd_AddCommand(&cmd_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 }