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