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