]> git.xonotic.org Git - xonotic/darkplaces.git/blob - r_shadow.c
Fix a few bugs detected by Cppcheck
[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->normalizevectors              = r_shadow_bouncegrid_normalizevectors.integer != 0;
1728         settings->subsamples                    = bound(1, r_shadow_bouncegrid_subsamples.integer, 4);
1729
1730         // bound the values for sanity
1731         settings->maxphotons = bound(1, settings->maxphotons, 25000000);
1732         settings->lightradiusscale = bound(0.0001f, settings->lightradiusscale, 1024.0f);
1733         settings->maxbounce = bound(0, settings->maxbounce, 16);
1734         settings->spacing[0] = bound(1, settings->spacing[0], 512);
1735         settings->spacing[1] = bound(1, settings->spacing[1], 512);
1736         settings->spacing[2] = bound(1, settings->spacing[2], 512);
1737 }
1738
1739 static void R_Shadow_BounceGrid_UpdateSpacing(void)
1740 {
1741         float m[16];
1742         int c[4];
1743         int resolution[3];
1744         int numpixels;
1745         vec3_t ispacing;
1746         vec3_t maxs;
1747         vec3_t mins;
1748         vec3_t size;
1749         vec3_t spacing;
1750         r_shadow_bouncegrid_settings_t *settings = &r_shadow_bouncegrid_state.settings;
1751
1752         // get the spacing values
1753         spacing[0] = settings->spacing[0];
1754         spacing[1] = settings->spacing[1];
1755         spacing[2] = settings->spacing[2];
1756         ispacing[0] = 1.0f / spacing[0];
1757         ispacing[1] = 1.0f / spacing[1];
1758         ispacing[2] = 1.0f / spacing[2];
1759
1760         // calculate texture size enclosing entire world bounds at the spacing
1761         if (r_refdef.scene.worldmodel)
1762         {
1763                 int lightindex;
1764                 int range;
1765                 qboolean bounds_set = false;
1766                 dlight_t *light;
1767                 rtlight_t *rtlight;
1768
1769                 // calculate bounds enclosing world lights as they should be noticably tighter 
1770                 // than the world bounds on maps with unlit monster containers (see e1m7 etc)
1771                 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1772                 for (lightindex = 0;lightindex < range;lightindex++)
1773                 {
1774                         const vec_t *rtlmins, *rtlmaxs;
1775
1776                         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1777                         if (!light)
1778                                 continue;
1779
1780                         rtlight = &light->rtlight;
1781                         rtlmins = rtlight->cullmins;
1782                         rtlmaxs = rtlight->cullmaxs;
1783
1784                         if (!bounds_set)
1785                         {
1786                                 VectorCopy(rtlmins, mins);
1787                                 VectorCopy(rtlmaxs, maxs);
1788                                 bounds_set = true;
1789                         }
1790                         else
1791                         {
1792                                 mins[0] = min(mins[0], rtlmins[0]);
1793                                 mins[1] = min(mins[1], rtlmins[1]);
1794                                 mins[2] = min(mins[2], rtlmins[2]);
1795                                 maxs[0] = max(maxs[0], rtlmaxs[0]);
1796                                 maxs[1] = max(maxs[1], rtlmaxs[1]);
1797                                 maxs[2] = max(maxs[2], rtlmaxs[2]);
1798                         }
1799                 }
1800
1801                 // limit to no larger than the world bounds
1802                 mins[0] = max(mins[0], r_refdef.scene.worldmodel->normalmins[0]);
1803                 mins[1] = max(mins[1], r_refdef.scene.worldmodel->normalmins[1]);
1804                 mins[2] = max(mins[2], r_refdef.scene.worldmodel->normalmins[2]);
1805                 maxs[0] = min(maxs[0], r_refdef.scene.worldmodel->normalmaxs[0]);
1806                 maxs[1] = min(maxs[1], r_refdef.scene.worldmodel->normalmaxs[1]);
1807                 maxs[2] = min(maxs[2], r_refdef.scene.worldmodel->normalmaxs[2]);
1808
1809                 VectorMA(mins, -2.0f, spacing, mins);
1810                 VectorMA(maxs, 2.0f, spacing, maxs);
1811         }
1812         else
1813         {
1814                 VectorSet(mins, -1048576.0f, -1048576.0f, -1048576.0f);
1815                 VectorSet(maxs,  1048576.0f,  1048576.0f,  1048576.0f);
1816         }
1817         VectorSubtract(maxs, mins, size);
1818         // now we can calculate the resolution we want
1819         c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
1820         c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
1821         c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
1822         // figure out the exact texture size (honoring power of 2 if required)
1823         resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1824         resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1825         resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1826         size[0] = spacing[0] * resolution[0];
1827         size[1] = spacing[1] * resolution[1];
1828         size[2] = spacing[2] * resolution[2];
1829
1830         // if dynamic we may or may not want to use the world bounds
1831         // if the dynamic size is smaller than the world bounds, use it instead
1832         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]))
1833         {
1834                 // we know the resolution we want
1835                 c[0] = r_shadow_bouncegrid_dynamic_x.integer;
1836                 c[1] = r_shadow_bouncegrid_dynamic_y.integer;
1837                 c[2] = r_shadow_bouncegrid_dynamic_z.integer;
1838                 // now we can calculate the texture size
1839                 resolution[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
1840                 resolution[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
1841                 resolution[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
1842                 size[0] = spacing[0] * resolution[0];
1843                 size[1] = spacing[1] * resolution[1];
1844                 size[2] = spacing[2] * resolution[2];
1845                 // center the rendering on the view
1846                 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
1847                 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
1848                 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
1849         }
1850
1851         // recalculate the maxs in case the resolution was not satisfactory
1852         VectorAdd(mins, size, maxs);
1853
1854         // check if this changed the texture size
1855         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);
1856         r_shadow_bouncegrid_state.directional = r_shadow_bouncegrid_state.settings.directionalshading;
1857         VectorCopy(mins, r_shadow_bouncegrid_state.mins);
1858         VectorCopy(maxs, r_shadow_bouncegrid_state.maxs);
1859         VectorCopy(size, r_shadow_bouncegrid_state.size);
1860         VectorCopy(spacing, r_shadow_bouncegrid_state.spacing);
1861         VectorCopy(ispacing, r_shadow_bouncegrid_state.ispacing);
1862         VectorCopy(resolution, r_shadow_bouncegrid_state.resolution);
1863
1864         // reallocate pixels for this update if needed...
1865         r_shadow_bouncegrid_state.pixelbands = settings->directionalshading ? 8 : 1;
1866         r_shadow_bouncegrid_state.pixelsperband = resolution[0]*resolution[1]*resolution[2];
1867         r_shadow_bouncegrid_state.bytesperband = r_shadow_bouncegrid_state.pixelsperband*4;
1868         numpixels = r_shadow_bouncegrid_state.pixelsperband*r_shadow_bouncegrid_state.pixelbands;
1869         if (r_shadow_bouncegrid_state.numpixels != numpixels)
1870         {
1871                 if (r_shadow_bouncegrid_state.texture) { R_FreeTexture(r_shadow_bouncegrid_state.texture);r_shadow_bouncegrid_state.texture = NULL; }
1872
1873                 r_shadow_bouncegrid_state.highpixels = NULL;
1874
1875                 if (r_shadow_bouncegrid_state.blurpixels[0]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL; }
1876                 if (r_shadow_bouncegrid_state.blurpixels[1]) { Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL; }
1877                 if (r_shadow_bouncegrid_state.u8pixels) { Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL; }
1878                 if (r_shadow_bouncegrid_state.fp16pixels) { Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL; }
1879                 if (r_shadow_bouncegrid_state.photons) { Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL; }
1880                 if (r_shadow_bouncegrid_state.photons_tasks) { Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL; }
1881                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
1882
1883                 r_shadow_bouncegrid_state.numpixels = numpixels;
1884         }
1885
1886         // update the bouncegrid matrix to put it in the world properly
1887         memset(m, 0, sizeof(m));
1888         m[0] = 1.0f / r_shadow_bouncegrid_state.size[0];
1889         m[3] = -r_shadow_bouncegrid_state.mins[0] * m[0];
1890         m[5] = 1.0f / r_shadow_bouncegrid_state.size[1];
1891         m[7] = -r_shadow_bouncegrid_state.mins[1] * m[5];
1892         m[10] = 1.0f / r_shadow_bouncegrid_state.size[2];
1893         m[11] = -r_shadow_bouncegrid_state.mins[2] * m[10];
1894         m[15] = 1.0f;
1895         Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegrid_state.matrix, m);
1896 }
1897
1898 static float R_Shadow_BounceGrid_RefractiveIndexAtPoint(vec3_t point)
1899 {
1900         // check material at shadoworigin to see what the initial refractive index should be
1901         int hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
1902         int skipsupercontentsmask = 0;
1903         int skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
1904         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);
1905         if (trace.starttexture && (trace.starttexture->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER)))
1906                 return trace.starttexture->refractive_index;
1907         else if (trace.startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
1908                 return 1.333f; // water
1909         else
1910                 return 1.0003f; // air
1911 }
1912
1913 // enumerate world rtlights and sum the overall amount of light in the world,
1914 // from that we can calculate a scaling factor to fairly distribute photons
1915 // to all the lights
1916 //
1917 // this modifies rtlight->photoncolor and rtlight->photons
1918 static void R_Shadow_BounceGrid_AssignPhotons_Task(taskqueue_task_t *t)
1919 {
1920         // get the range of light numbers we'll be looping over:
1921         // range = static lights
1922         // range1 = dynamic lights (optional)
1923         // range2 = range + range1
1924         unsigned int range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
1925         unsigned int range1 = r_shadow_bouncegrid_state.settings.staticmode ? 0 : r_refdef.scene.numlights;
1926         unsigned int range2 = range + range1;
1927         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
1928
1929         float normalphotonscaling;
1930         float photonscaling;
1931         float photonintensity;
1932         float photoncount = 0.0f;
1933         float lightintensity;
1934         float radius;
1935         float s;
1936         float w;
1937         vec3_t cullmins;
1938         vec3_t cullmaxs;
1939         unsigned int lightindex;
1940         dlight_t *light;
1941         rtlight_t *rtlight;
1942         int shootparticles;
1943         int shotparticles;
1944         float bounceminimumintensity2;
1945         float startrefractiveindex;
1946         unsigned int seed;
1947         randomseed_t randomseed;
1948         vec3_t baseshotcolor;
1949
1950         normalphotonscaling = 1.0f / max(0.0000001f, r_shadow_bouncegrid_state.settings.energyperphoton);
1951         for (lightindex = 0;lightindex < range2;lightindex++)
1952         {
1953                 if (lightindex < range)
1954                 {
1955                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
1956                         if (!light)
1957                                 continue;
1958                         rtlight = &light->rtlight;
1959                         VectorClear(rtlight->bouncegrid_photoncolor);
1960                         rtlight->bouncegrid_photons = 0;
1961                         rtlight->bouncegrid_hits = 0;
1962                         rtlight->bouncegrid_traces = 0;
1963                         rtlight->bouncegrid_effectiveradius = 0;
1964                         if (!(light->flags & flag))
1965                                 continue;
1966                         if (r_shadow_bouncegrid_state.settings.staticmode)
1967                         {
1968                                 // when static, we skip styled lights because they tend to change...
1969                                 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
1970                                         continue;
1971                         }
1972                         else if (r_shadow_debuglight.integer >= 0 && (int)lightindex != r_shadow_debuglight.integer)
1973                                 continue;
1974                 }
1975                 else
1976                 {
1977                         rtlight = r_refdef.scene.lights[lightindex - range];
1978                         VectorClear(rtlight->bouncegrid_photoncolor);
1979                         rtlight->bouncegrid_photons = 0;
1980                         rtlight->bouncegrid_hits = 0;
1981                         rtlight->bouncegrid_traces = 0;
1982                         rtlight->bouncegrid_effectiveradius = 0;
1983                 }
1984                 // draw only visible lights (major speedup)
1985                 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
1986                 cullmins[0] = rtlight->shadoworigin[0] - radius;
1987                 cullmins[1] = rtlight->shadoworigin[1] - radius;
1988                 cullmins[2] = rtlight->shadoworigin[2] - radius;
1989                 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
1990                 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
1991                 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
1992                 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
1993                 if (!r_shadow_bouncegrid_state.settings.staticmode)
1994                 {
1995                         // skip if the expanded light box does not touch any visible leafs
1996                         if (r_refdef.scene.worldmodel
1997                                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
1998                                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
1999                                 continue;
2000                         // skip if the expanded light box is not visible to traceline
2001                         // note that PrepareLight already did this check but for a smaller box, so we
2002                         // end up casting more traces per frame per light when using bouncegrid, which
2003                         // is probably fine (and they use the same timer)
2004                         if (r_shadow_culllights_trace.integer)
2005                         {
2006                                 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))
2007                                         rtlight->trace_timer = realtime;
2008                                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
2009                                         continue;
2010                         }
2011                         // skip if expanded light box is offscreen
2012                         if (R_CullBox(cullmins, cullmaxs))
2013                                 continue;
2014                         // skip if overall light intensity is zero
2015                         if (w * VectorLength2(rtlight->color) == 0.0f)
2016                                 continue;
2017                 }
2018                 // a light that does not emit any light before style is applied, can be
2019                 // skipped entirely (it may just be a corona)
2020                 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2021                         continue;
2022                 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2023                 VectorScale(rtlight->color, w, rtlight->bouncegrid_photoncolor);
2024                 // skip lights that will emit no photons
2025                 if (!VectorLength2(rtlight->bouncegrid_photoncolor))
2026                         continue;
2027                 // shoot particles from this light
2028                 // use a calculation for the number of particles that will not
2029                 // vary with lightstyle, otherwise we get randomized particle
2030                 // distribution, the seeded random is only consistent for a
2031                 // consistent number of particles on this light...
2032                 s = rtlight->radius;
2033                 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2034                 if (lightindex >= range)
2035                         lightintensity *= r_shadow_bouncegrid_state.settings.dlightparticlemultiplier;
2036                 rtlight->bouncegrid_photons = lightintensity * s * s * normalphotonscaling;
2037                 photoncount += rtlight->bouncegrid_photons;
2038                 VectorScale(rtlight->bouncegrid_photoncolor, r_shadow_bouncegrid_state.settings.particleintensity * r_shadow_bouncegrid_state.settings.energyperphoton, rtlight->bouncegrid_photoncolor);
2039                 // if the lightstyle happens to be off right now, we can skip actually
2040                 // firing the photons, but we did have to count them in the total.
2041                 //if (VectorLength2(rtlight->photoncolor) == 0.0f)
2042                 //      rtlight->bouncegrid_photons = 0;
2043         }
2044         // the user provided an energyperphoton value which we try to use
2045         // if that results in too many photons to shoot this frame, then we cap it
2046         // which causes photons to appear/disappear from frame to frame, so we don't
2047         // like doing that in the typical case
2048         photonscaling = 1.0f;
2049         photonintensity = 1.0f;
2050         if (photoncount > r_shadow_bouncegrid_state.settings.maxphotons)
2051         {
2052                 photonscaling = r_shadow_bouncegrid_state.settings.maxphotons / photoncount;
2053                 photonintensity = 1.0f / photonscaling;
2054         }
2055
2056         // modify the lights to reflect our computed scaling
2057         for (lightindex = 0; lightindex < range2; lightindex++)
2058         {
2059                 if (lightindex < range)
2060                 {
2061                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2062                         if (!light)
2063                                 continue;
2064                         rtlight = &light->rtlight;
2065                 }
2066                 else
2067                         rtlight = r_refdef.scene.lights[lightindex - range];
2068                 rtlight->bouncegrid_photons *= photonscaling;
2069                 VectorScale(rtlight->bouncegrid_photoncolor, photonintensity, rtlight->bouncegrid_photoncolor);
2070         }
2071
2072         // compute a seed for the unstable random modes
2073         Math_RandomSeed_FromInts(&randomseed, 0, 0, 0, realtime * 1000.0);
2074         seed = realtime * 1000.0;
2075
2076         for (lightindex = 0; lightindex < range2; lightindex++)
2077         {
2078                 if (lightindex < range)
2079                 {
2080                         light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2081                         if (!light)
2082                                 continue;
2083                         rtlight = &light->rtlight;
2084                 }
2085                 else
2086                         rtlight = r_refdef.scene.lights[lightindex - range];
2087                 // note that this code used to keep track of residual photons and
2088                 // distribute them evenly to achieve exactly a desired photon count,
2089                 // but that caused unwanted flickering in dynamic mode
2090                 shootparticles = (int)floor(rtlight->bouncegrid_photons);
2091                 // skip if we won't be shooting any photons
2092                 if (!shootparticles)
2093                         continue;
2094                 radius = rtlight->radius * r_shadow_bouncegrid_state.settings.lightradiusscale;
2095                 //s = settings.particleintensity / shootparticles;
2096                 //VectorScale(rtlight->bouncegrid_photoncolor, s, baseshotcolor);
2097                 VectorCopy(rtlight->bouncegrid_photoncolor, baseshotcolor);
2098                 if (VectorLength2(baseshotcolor) <= 0.0f)
2099                         continue;
2100                 r_refdef.stats[r_stat_bouncegrid_lights]++;
2101                 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2102                 // we stop caring about bounces once the brightness goes below this fraction of the original intensity
2103                 bounceminimumintensity2 = VectorLength(baseshotcolor) * r_shadow_bouncegrid_state.settings.bounceminimumintensity2;
2104
2105                 // check material at shadoworigin to see what the initial refractive index should be
2106                 startrefractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(rtlight->shadoworigin);
2107
2108                 // for seeded random we start the RNG with the position of the light
2109                 if (r_shadow_bouncegrid_state.settings.rng_seed >= 0)
2110                 {
2111                         union
2112                         {
2113                                 unsigned int i[4];
2114                                 float f[4];
2115                         }
2116                         u;
2117                         u.f[0] = rtlight->shadoworigin[0];
2118                         u.f[1] = rtlight->shadoworigin[1];
2119                         u.f[2] = rtlight->shadoworigin[2];
2120                         u.f[3] = 1;
2121                         switch (r_shadow_bouncegrid_state.settings.rng_type)
2122                         {
2123                         default:
2124                         case 0:
2125                                 // we have to shift the seed provided by the user because the result must be odd
2126                                 Math_RandomSeed_FromInts(&randomseed, u.i[0], u.i[1], u.i[2], u.i[3] ^ (r_shadow_bouncegrid_state.settings.rng_seed << 1));
2127                                 break;
2128                         case 1:
2129                                 seed = u.i[0] ^ u.i[1] ^ u.i[2] ^ u.i[3] ^ r_shadow_bouncegrid_state.settings.rng_seed;
2130                                 break;
2131                         }
2132                 }
2133
2134                 for (shotparticles = 0; shotparticles < shootparticles && r_shadow_bouncegrid_state.numphotons < r_shadow_bouncegrid_state.settings.maxphotons; shotparticles++)
2135                 {
2136                         r_shadow_bouncegrid_photon_t *p = r_shadow_bouncegrid_state.photons + r_shadow_bouncegrid_state.numphotons++;
2137                         VectorCopy(baseshotcolor, p->color);
2138                         VectorCopy(rtlight->shadoworigin, p->start);
2139                         switch (r_shadow_bouncegrid_state.settings.rng_type)
2140                         {
2141                         default:
2142                         case 0:
2143                                 // figure out a random direction for the initial photon to go
2144                                 VectorLehmerRandom(&randomseed, p->end);
2145                                 break;
2146                         case 1:
2147                                 // figure out a random direction for the initial photon to go
2148                                 VectorCheeseRandom(seed, p->end);
2149                                 break;
2150                         }
2151
2152                         // we want a uniform distribution spherically, not merely within the sphere
2153                         if (r_shadow_bouncegrid_state.settings.normalizevectors)
2154                                 VectorNormalize(p->end);
2155
2156                         VectorMA(p->start, radius, p->end, p->end);
2157                         p->bounceminimumintensity2 = bounceminimumintensity2;
2158                         p->startrefractiveindex = startrefractiveindex;
2159                         p->numpaths = 0;
2160                 }
2161         }
2162
2163         t->done = 1;
2164 }
2165
2166 static void R_Shadow_BounceGrid_Slice(int zi)
2167 {
2168         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2169         int xi, yi; // pixel increments
2170         float color[32] = { 0 };
2171         float radius = r_shadow_bouncegrid_state.settings.lightpathsize;
2172         float iradius = 1.0f / radius;
2173         int slicemins[3], slicemaxs[3];
2174         int resolution[3];
2175         int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2176         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2177         int photonindex;
2178         int samples = r_shadow_bouncegrid_state.settings.subsamples;
2179         float isamples = 1.0f / samples;
2180         float samplescolorscale = isamples * isamples * isamples;
2181
2182         // we use these a lot, so get a local copy
2183         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2184
2185         for (photonindex = 0; photonindex < r_shadow_bouncegrid_state.numphotons; photonindex++)
2186         {
2187                 r_shadow_bouncegrid_photon_t *photon = r_shadow_bouncegrid_state.photons + photonindex;
2188                 int pathindex;
2189                 for (pathindex = 0; pathindex < photon->numpaths; pathindex++)
2190                 {
2191                         r_shadow_bouncegrid_photon_path_t *path = photon->paths + pathindex;
2192                         float pathstart[3], pathend[3], pathmins[3], pathmaxs[3], pathdelta[3], pathdir[3], pathlength2, pathilength;
2193
2194                         VectorSubtract(path->start, r_shadow_bouncegrid_state.mins, pathstart);
2195                         VectorSubtract(path->end, r_shadow_bouncegrid_state.mins, pathend);
2196
2197                         pathmins[2] = min(pathstart[2], pathend[2]);
2198                         slicemins[2] = (int)floor((pathmins[2] - radius) * r_shadow_bouncegrid_state.ispacing[2]);
2199                         pathmaxs[2] = max(pathstart[2], pathend[2]);
2200                         slicemaxs[2] = (int)floor((pathmaxs[2] + radius) * r_shadow_bouncegrid_state.ispacing[2] + 1);
2201
2202                         // skip if the path doesn't touch this slice
2203                         if (zi < slicemins[2] || zi >= slicemaxs[2])
2204                                 continue;
2205
2206                         pathmins[0] = min(pathstart[0], pathend[0]);
2207                         slicemins[0] = (int)floor((pathmins[0] - radius) * r_shadow_bouncegrid_state.ispacing[0]);
2208                         slicemins[0] = max(slicemins[0], 1);
2209                         pathmaxs[0] = max(pathstart[0], pathend[0]);
2210                         slicemaxs[0] = (int)floor((pathmaxs[0] + radius) * r_shadow_bouncegrid_state.ispacing[0]);
2211                         slicemaxs[0] = min(slicemaxs[0], resolution[0] - 1);
2212
2213                         pathmins[1] = min(pathstart[1], pathend[1]);
2214                         slicemins[1] = (int)floor((pathmins[1] - radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2215                         slicemins[1] = max(slicemins[1], 1);
2216                         pathmaxs[1] = max(pathstart[1], pathend[1]);
2217                         slicemaxs[1] = (int)floor((pathmaxs[1] + radius) * r_shadow_bouncegrid_state.ispacing[1] + 1);
2218                         slicemaxs[1] = min(slicemaxs[1], resolution[1] - 1);
2219
2220                         // skip if the path is out of bounds on X or Y
2221                         if (slicemins[0] >= slicemaxs[0] || slicemins[1] >= slicemaxs[1])
2222                                 continue;
2223
2224                         // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2225                         // accumulate average shotcolor
2226                         VectorSubtract(pathend, pathstart, pathdelta);
2227                         pathlength2 = VectorLength2(pathdelta);
2228                         pathilength = pathlength2 > 0.0f ? 1.0f / sqrt(pathlength2) : 0.0f;
2229                         VectorScale(pathdelta, pathilength, pathdir);
2230                         // the color is scaled by the number of subsamples
2231                         color[0] = path->color[0] * samplescolorscale;
2232                         color[1] = path->color[1] * samplescolorscale;
2233                         color[2] = path->color[2] * samplescolorscale;
2234                         color[3] = 0.0f;
2235                         if (pixelbands > 1)
2236                         {
2237                                 // store bentnormal in case the shader has a use for it,
2238                                 // bentnormal is an intensity-weighted average of the directions,
2239                                 // and will be normalized on conversion to texture pixels.
2240                                 float intensity = VectorLength(color);
2241                                 color[4] = pathdir[0] * intensity;
2242                                 color[5] = pathdir[1] * intensity;
2243                                 color[6] = pathdir[2] * intensity;
2244                                 color[7] = intensity;
2245                                 // for each color component (R, G, B) calculate the amount that a
2246                                 // direction contributes
2247                                 color[8] = color[0] * max(0.0f, pathdir[0]);
2248                                 color[9] = color[0] * max(0.0f, pathdir[1]);
2249                                 color[10] = color[0] * max(0.0f, pathdir[2]);
2250                                 color[11] = 0.0f;
2251                                 color[12] = color[1] * max(0.0f, pathdir[0]);
2252                                 color[13] = color[1] * max(0.0f, pathdir[1]);
2253                                 color[14] = color[1] * max(0.0f, pathdir[2]);
2254                                 color[15] = 0.0f;
2255                                 color[16] = color[2] * max(0.0f, pathdir[0]);
2256                                 color[17] = color[2] * max(0.0f, pathdir[1]);
2257                                 color[18] = color[2] * max(0.0f, pathdir[2]);
2258                                 color[19] = 0.0f;
2259                                 // and do the same for negative directions
2260                                 color[20] = color[0] * max(0.0f, -pathdir[0]);
2261                                 color[21] = color[0] * max(0.0f, -pathdir[1]);
2262                                 color[22] = color[0] * max(0.0f, -pathdir[2]);
2263                                 color[23] = 0.0f;
2264                                 color[24] = color[1] * max(0.0f, -pathdir[0]);
2265                                 color[25] = color[1] * max(0.0f, -pathdir[1]);
2266                                 color[26] = color[1] * max(0.0f, -pathdir[2]);
2267                                 color[27] = 0.0f;
2268                                 color[28] = color[2] * max(0.0f, -pathdir[0]);
2269                                 color[29] = color[2] * max(0.0f, -pathdir[1]);
2270                                 color[30] = color[2] * max(0.0f, -pathdir[2]);
2271                                 color[31] = 0.0f;
2272                         }
2273
2274                         for (yi = slicemins[1]; yi < slicemaxs[1]; yi++)
2275                         {
2276                                 for (xi = slicemins[0]; xi < slicemaxs[0]; xi++)
2277                                 {
2278                                         float sample[3], diff[3], nearest[3], along, distance2;
2279                                         float *p = highpixels + 4 * ((zi * resolution[1] + yi) * resolution[0] + xi);
2280                                         int xs, ys, zs;
2281                                         // loop over the subsamples
2282                                         for (zs = 0; zs < samples; zs++)
2283                                         {
2284                                                 sample[2] = (zi + (zs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[2];
2285                                                 for (ys = 0; ys < samples; ys++)
2286                                                 {
2287                                                         sample[1] = (yi + (ys + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[1];
2288                                                         for (xs = 0; xs < samples; xs++)
2289                                                         {
2290                                                                 sample[0] = (xi + (xs + 0.5f) * isamples) * r_shadow_bouncegrid_state.spacing[0];
2291
2292                                                                 // measure distance from subsample to line segment and see if it is within radius
2293                                                                 along = DotProduct(sample, pathdir) * pathilength;
2294                                                                 if (along <= 0)
2295                                                                         VectorCopy(pathstart, nearest);
2296                                                                 else if (along >= 1)
2297                                                                         VectorCopy(pathend, nearest);
2298                                                                 else
2299                                                                         VectorLerp(pathstart, along, pathend, nearest);
2300                                                                 VectorSubtract(sample, nearest, diff);
2301                                                                 VectorScale(diff, iradius, diff);
2302                                                                 distance2 = VectorLength2(diff);
2303                                                                 if (distance2 < 1.0f)
2304                                                                 {
2305                                                                         // contribute some color to this pixel, across all bands
2306                                                                         float w = 1.0f - sqrt(distance2);
2307                                                                         int band;
2308                                                                         w *= w;
2309                                                                         if (pixelbands > 1)
2310                                                                         {
2311                                                                                 // small optimization for alpha - only color[7] is non-zero, so skip the rest of the alpha elements.
2312                                                                                 p[pixelsperband * 4 + 3] += color[7] * w;
2313                                                                         }
2314                                                                         for (band = 0; band < pixelbands; band++)
2315                                                                         {
2316                                                                                 // add to the pixel color (RGB only - see above)
2317                                                                                 p[band * pixelsperband * 4 + 0] += color[band * 4 + 0] * w;
2318                                                                                 p[band * pixelsperband * 4 + 1] += color[band * 4 + 1] * w;
2319                                                                                 p[band * pixelsperband * 4 + 2] += color[band * 4 + 2] * w;
2320                                                                         }
2321                                                                 }
2322                                                         }
2323                                                 }
2324                                         }
2325                                 }
2326                         }
2327                 }
2328         }
2329 }
2330
2331 static void R_Shadow_BounceGrid_Slice_Task(taskqueue_task_t *t)
2332 {
2333         R_Shadow_BounceGrid_Slice((int)t->i[0]);
2334         t->done = 1;
2335 }
2336
2337 static void R_Shadow_BounceGrid_EnqueueSlices_Task(taskqueue_task_t *t)
2338 {
2339         int i, slices;
2340         // we need to wait for the texture clear to finish before we start adding light to it
2341         if (r_shadow_bouncegrid_state.cleartex_task.done == 0)
2342         {
2343                 TaskQueue_Yield(t);
2344                 return;
2345         }
2346         slices = r_shadow_bouncegrid_state.resolution[2] - 2;
2347         for (i = 0; i < slices; i++)
2348                 TaskQueue_Setup(r_shadow_bouncegrid_state.slices_tasks + i, NULL, R_Shadow_BounceGrid_Slice_Task, i + 1, 0, NULL, NULL);
2349         TaskQueue_Enqueue(slices, r_shadow_bouncegrid_state.slices_tasks);
2350         TaskQueue_Setup(&r_shadow_bouncegrid_state.slices_done_task, NULL, TaskQueue_Task_CheckTasksDone, slices, 0, r_shadow_bouncegrid_state.slices_tasks, 0);
2351         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.slices_done_task);
2352         t->done = 1;
2353 }
2354
2355 static void R_Shadow_BounceGrid_BlurPixelsInDirection(const float *inpixels, float *outpixels, int off)
2356 {
2357         const float *inpixel;
2358         float *outpixel;
2359         int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2360         int pixelband;
2361         unsigned int index;
2362         unsigned int x, y, z;
2363         unsigned int resolution[3];
2364         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2365         for (pixelband = 0;pixelband < pixelbands;pixelband++)
2366         {
2367                 for (z = 1;z < resolution[2]-1;z++)
2368                 {
2369                         for (y = 1;y < resolution[1]-1;y++)
2370                         {
2371                                 x = 1;
2372                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2373                                 inpixel = inpixels + 4*index;
2374                                 outpixel = outpixels + 4*index;
2375                                 for (;x < resolution[0]-1;x++, inpixel += 4, outpixel += 4)
2376                                 {
2377                                         outpixel[0] = (inpixel[0] + inpixel[  off] + inpixel[0-off]) * (1.0f / 3.0);
2378                                         outpixel[1] = (inpixel[1] + inpixel[1+off] + inpixel[1-off]) * (1.0f / 3.0);
2379                                         outpixel[2] = (inpixel[2] + inpixel[2+off] + inpixel[2-off]) * (1.0f / 3.0);
2380                                         outpixel[3] = (inpixel[3] + inpixel[3+off] + inpixel[3-off]) * (1.0f / 3.0);
2381                                 }
2382                         }
2383                 }
2384         }
2385 }
2386
2387 static void R_Shadow_BounceGrid_BlurPixels_Task(taskqueue_task_t *t)
2388 {
2389         float *pixels[4];
2390         unsigned int resolution[3];
2391         if (r_shadow_bouncegrid_state.settings.blur)
2392         {
2393                 VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2394
2395                 pixels[0] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2396                 pixels[1] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2397                 pixels[2] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2398                 pixels[3] = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index ^ 1];
2399
2400                 // blur on X
2401                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[0], pixels[1], 4);
2402                 // blur on Y
2403                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[1], pixels[2], resolution[0] * 4);
2404                 // blur on Z
2405                 R_Shadow_BounceGrid_BlurPixelsInDirection(pixels[2], pixels[3], resolution[0] * resolution[1] * 4);
2406
2407                 // toggle the state, highpixels now points to pixels[3] result
2408                 r_shadow_bouncegrid_state.highpixels_index ^= 1;
2409                 r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2410         }
2411         t->done = 1;
2412 }
2413
2414 static void R_Shadow_BounceGrid_ConvertPixelsAndUpload(void)
2415 {
2416         int floatcolors = r_shadow_bouncegrid_state.settings.floatcolors;
2417         unsigned char *pixelsbgra8 = NULL;
2418         unsigned char *pixelbgra8;
2419         unsigned short *pixelsrgba16f = NULL;
2420         unsigned short *pixelrgba16f;
2421         float *pixelsrgba32f = NULL;
2422         float *highpixels = r_shadow_bouncegrid_state.highpixels;
2423         float *highpixel;
2424         float *bandpixel;
2425         unsigned int pixelsperband = r_shadow_bouncegrid_state.pixelsperband;
2426         unsigned int pixelbands = r_shadow_bouncegrid_state.pixelbands;
2427         unsigned int pixelband;
2428         unsigned int x, y, z;
2429         unsigned int index, bandindex;
2430         unsigned int resolution[3];
2431         int c[4];
2432         VectorCopy(r_shadow_bouncegrid_state.resolution, resolution);
2433
2434         if (r_shadow_bouncegrid_state.createtexture && r_shadow_bouncegrid_state.texture)
2435         {
2436                 R_FreeTexture(r_shadow_bouncegrid_state.texture);
2437                 r_shadow_bouncegrid_state.texture = NULL;
2438         }
2439
2440         // if bentnormals exist, we need to normalize and bias them for the shader
2441         if (pixelbands > 1)
2442         {
2443                 pixelband = 1;
2444                 for (z = 0;z < resolution[2]-1;z++)
2445                 {
2446                         for (y = 0;y < resolution[1]-1;y++)
2447                         {
2448                                 x = 1;
2449                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2450                                 highpixel = highpixels + 4*index;
2451                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2452                                 {
2453                                         // only convert pixels that were hit by photons
2454                                         if (highpixel[3] != 0.0f)
2455                                                 VectorNormalize(highpixel);
2456                                         VectorSet(highpixel, highpixel[0] * 0.5f + 0.5f, highpixel[1] * 0.5f + 0.5f, highpixel[2] * 0.5f + 0.5f);
2457                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2458                                 }
2459                         }
2460                 }
2461         }
2462
2463         // start by clearing the pixels array - we won't be writing to all of it
2464         //
2465         // then process only the pixels that have at least some color, skipping
2466         // the higher bands for speed on pixels that are black
2467         switch (floatcolors)
2468         {
2469         case 0:
2470                 if (r_shadow_bouncegrid_state.u8pixels == NULL)
2471                         r_shadow_bouncegrid_state.u8pixels = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned char[4]));
2472                 pixelsbgra8 = r_shadow_bouncegrid_state.u8pixels;
2473                 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2474                 {
2475                         if (pixelband == 1)
2476                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 128, r_shadow_bouncegrid_state.bytesperband);
2477                         else
2478                                 memset(pixelsbgra8 + pixelband * r_shadow_bouncegrid_state.bytesperband, 0, r_shadow_bouncegrid_state.bytesperband);
2479                 }
2480                 for (z = 1;z < resolution[2]-1;z++)
2481                 {
2482                         for (y = 1;y < resolution[1]-1;y++)
2483                         {
2484                                 x = 1;
2485                                 pixelband = 0;
2486                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2487                                 highpixel = highpixels + 4*index;
2488                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2489                                 {
2490                                         // only convert pixels that were hit by photons
2491                                         if (VectorLength2(highpixel))
2492                                         {
2493                                                 // normalize the bentnormal now
2494                                                 if (pixelbands > 1)
2495                                                 {
2496                                                         VectorNormalize(highpixel + pixelsperband * 4);
2497                                                         highpixel[pixelsperband * 4 + 3] = 1.0f;
2498                                                 }
2499                                                 // process all of the pixelbands for this pixel
2500                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2501                                                 {
2502                                                         pixelbgra8 = pixelsbgra8 + 4*bandindex;
2503                                                         bandpixel = highpixels + 4*bandindex;
2504                                                         c[0] = (int)(bandpixel[0]*256.0f);
2505                                                         c[1] = (int)(bandpixel[1]*256.0f);
2506                                                         c[2] = (int)(bandpixel[2]*256.0f);
2507                                                         c[3] = (int)(bandpixel[3]*256.0f);
2508                                                         pixelbgra8[2] = (unsigned char)bound(0, c[0], 255);
2509                                                         pixelbgra8[1] = (unsigned char)bound(0, c[1], 255);
2510                                                         pixelbgra8[0] = (unsigned char)bound(0, c[2], 255);
2511                                                         pixelbgra8[3] = (unsigned char)bound(0, c[3], 255);
2512                                                 }
2513                                         }
2514                                 }
2515                         }
2516                 }
2517
2518                 if (!r_shadow_bouncegrid_state.createtexture)
2519                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, pixelsbgra8, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2520                 else
2521                         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);
2522                 break;
2523         case 1:
2524                 if (r_shadow_bouncegrid_state.fp16pixels == NULL)
2525                         r_shadow_bouncegrid_state.fp16pixels = (unsigned short *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2526                 pixelsrgba16f = r_shadow_bouncegrid_state.fp16pixels;
2527                 memset(pixelsrgba16f, 0, r_shadow_bouncegrid_state.numpixels * sizeof(unsigned short[4]));
2528                 for (z = 1;z < resolution[2]-1;z++)
2529                 {
2530                         for (y = 1;y < resolution[1]-1;y++)
2531                         {
2532                                 x = 1;
2533                                 pixelband = 0;
2534                                 index = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x;
2535                                 highpixel = highpixels + 4*index;
2536                                 for (;x < resolution[0]-1;x++, index++, highpixel += 4)
2537                                 {
2538                                         // only convert pixels that were hit by photons
2539                                         if (VectorLength2(highpixel))
2540                                         {
2541                                                 // process all of the pixelbands for this pixel
2542                                                 for (pixelband = 0, bandindex = index;pixelband < pixelbands;pixelband++, bandindex += pixelsperband)
2543                                                 {
2544                                                         // time to have fun with IEEE 754 bit hacking...
2545                                                         union {
2546                                                                 float f[4];
2547                                                                 unsigned int raw[4];
2548                                                         } u;
2549                                                         pixelrgba16f = pixelsrgba16f + 4*bandindex;
2550                                                         bandpixel = highpixels + 4*bandindex;
2551                                                         VectorCopy4(bandpixel, u.f);
2552                                                         VectorCopy4(u.raw, c);
2553                                                         // this math supports negative numbers, snaps denormals to zero
2554                                                         //pixelrgba16f[0] = (unsigned short)(((c[0] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[0] - 0x38000000) >> 13) & 0x7FFF) | ((c[0] >> 16) & 0x8000));
2555                                                         //pixelrgba16f[1] = (unsigned short)(((c[1] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[1] - 0x38000000) >> 13) & 0x7FFF) | ((c[1] >> 16) & 0x8000));
2556                                                         //pixelrgba16f[2] = (unsigned short)(((c[2] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[2] - 0x38000000) >> 13) & 0x7FFF) | ((c[2] >> 16) & 0x8000));
2557                                                         //pixelrgba16f[3] = (unsigned short)(((c[3] & 0x7FFFFFFF) < 0x38000000) ? 0 : (((c[3] - 0x38000000) >> 13) & 0x7FFF) | ((c[3] >> 16) & 0x8000));
2558                                                         // this math does not support negative
2559                                                         pixelrgba16f[0] = (unsigned short)((c[0] < 0x38000000) ? 0 : ((c[0] - 0x38000000) >> 13));
2560                                                         pixelrgba16f[1] = (unsigned short)((c[1] < 0x38000000) ? 0 : ((c[1] - 0x38000000) >> 13));
2561                                                         pixelrgba16f[2] = (unsigned short)((c[2] < 0x38000000) ? 0 : ((c[2] - 0x38000000) >> 13));
2562                                                         pixelrgba16f[3] = (unsigned short)((c[3] < 0x38000000) ? 0 : ((c[3] - 0x38000000) >> 13));
2563                                                 }
2564                                         }
2565                                 }
2566                         }
2567                 }
2568
2569                 if (!r_shadow_bouncegrid_state.createtexture)
2570                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba16f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2571                 else
2572                         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);
2573                 break;
2574         case 2:
2575                 // our native format happens to match, so this is easy.
2576                 pixelsrgba32f = highpixels;
2577
2578                 if (!r_shadow_bouncegrid_state.createtexture)
2579                         R_UpdateTexture(r_shadow_bouncegrid_state.texture, (const unsigned char *)pixelsrgba32f, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2580                 else
2581                         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);
2582                 break;
2583         }
2584
2585         r_shadow_bouncegrid_state.lastupdatetime = realtime;
2586 }
2587
2588 void R_Shadow_BounceGrid_ClearTex_Task(taskqueue_task_t *t)
2589 {
2590         memset(r_shadow_bouncegrid_state.highpixels, 0, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2591         t->done = 1;
2592 }
2593
2594 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)
2595 {
2596         int hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask;
2597         vec3_t shothit;
2598         vec3_t surfacenormal;
2599         vec3_t reflectstart, reflectend, reflectcolor;
2600         vec3_t refractstart, refractend, refractcolor;
2601         vec_t s;
2602         float reflectamount = 1.0f;
2603         trace_t cliptrace;
2604         // figure out what we want to interact with
2605         hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2606         skipsupercontentsmask = 0;
2607         skipmaterialflagsmask = MATERIALFLAG_CUSTOMBLEND;
2608         //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2609         //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2610         if (r_shadow_bouncegrid_state.settings.staticmode || r_shadow_bouncegrid_state.settings.rng_seed < 0 || r_shadow_bouncegrid_threaded.integer)
2611         {
2612                 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2613                 // non-stable random in dynamic mode also never reuses a direction, so there's no reason to cache it
2614                 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);
2615         }
2616         else
2617         {
2618                 // dynamic mode fires many rays and most will match the cache from the previous frame
2619                 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);
2620         }
2621         VectorCopy(cliptrace.endpos, shothit);
2622         if ((remainingbounces == r_shadow_bouncegrid_state.settings.maxbounce || r_shadow_bouncegrid_state.settings.includedirectlighting) && p->numpaths < PHOTON_MAX_PATHS)
2623         {
2624                 qboolean notculled = true;
2625                 // cull paths that fail R_CullBox in dynamic mode
2626                 if (!r_shadow_bouncegrid_state.settings.staticmode
2627                         && r_shadow_bouncegrid_dynamic_culllightpaths.integer)
2628                 {
2629                         vec3_t cullmins, cullmaxs;
2630                         cullmins[0] = min(shotstart[0], shothit[0]) - r_shadow_bouncegrid_state.settings.spacing[0] - r_shadow_bouncegrid_state.settings.lightpathsize;
2631                         cullmins[1] = min(shotstart[1], shothit[1]) - r_shadow_bouncegrid_state.settings.spacing[1] - r_shadow_bouncegrid_state.settings.lightpathsize;
2632                         cullmins[2] = min(shotstart[2], shothit[2]) - r_shadow_bouncegrid_state.settings.spacing[2] - r_shadow_bouncegrid_state.settings.lightpathsize;
2633                         cullmaxs[0] = max(shotstart[0], shothit[0]) + r_shadow_bouncegrid_state.settings.spacing[0] + r_shadow_bouncegrid_state.settings.lightpathsize;
2634                         cullmaxs[1] = max(shotstart[1], shothit[1]) + r_shadow_bouncegrid_state.settings.spacing[1] + r_shadow_bouncegrid_state.settings.lightpathsize;
2635                         cullmaxs[2] = max(shotstart[2], shothit[2]) + r_shadow_bouncegrid_state.settings.spacing[2] + r_shadow_bouncegrid_state.settings.lightpathsize;
2636                         if (R_CullBox(cullmins, cullmaxs))
2637                                 notculled = false;
2638                 }
2639                 if (notculled)
2640                 {
2641                         r_shadow_bouncegrid_photon_path_t *path = p->paths + p->numpaths++;
2642                         VectorCopy(shotstart, path->start);
2643                         VectorCopy(shothit, path->end);
2644                         VectorCopy(shotcolor, path->color);
2645                 }
2646         }
2647         if (cliptrace.fraction < 1.0f && remainingbounces > 0)
2648         {
2649                 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2650                 // also clamp the resulting color to never add energy, even if the user requests extreme values
2651                 VectorCopy(cliptrace.plane.normal, surfacenormal);
2652                 VectorSet(reflectcolor, 0.5f, 0.5f, 0.5f);
2653                 VectorClear(refractcolor);
2654                 // FIXME: we need to determine the exact triangle, vertex color and texcoords and texture color and texture normal for the impacted point
2655                 if (cliptrace.hittexture)
2656                 {
2657                         if (cliptrace.hittexture->currentskinframe)
2658                                 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, reflectcolor);
2659                         if (cliptrace.hittexture->currentalpha < 1.0f && (cliptrace.hittexture->currentmaterialflags & (MATERIALFLAG_ALPHA | MATERIALFLAG_ALPHATEST)))
2660                         {
2661                                 reflectamount *= cliptrace.hittexture->currentalpha;
2662                                 if (cliptrace.hittexture->currentskinframe)
2663                                         reflectamount *= cliptrace.hittexture->currentskinframe->avgcolor[3];
2664                         }
2665                         if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
2666                         {
2667                                 float Fresnel;
2668                                 vec3_t lightdir;
2669                                 //reflectchance = pow(min(1.0f, 1.0f - cliptrace.
2670                                 VectorSubtract(shotstart, shotend, lightdir);
2671                                 VectorNormalize(lightdir);
2672                                 Fresnel = min(1.0f, 1.0f - DotProduct(lightdir, surfacenormal));
2673                                 Fresnel = Fresnel * Fresnel * (cliptrace.hittexture->reflectmax - cliptrace.hittexture->reflectmin) + cliptrace.hittexture->reflectmin;
2674                                 reflectamount *= Fresnel;
2675                                 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2676                         }
2677                         if (cliptrace.hittexture->currentmaterialflags & MATERIALFLAG_REFRACTION)
2678                                 VectorCopy(cliptrace.hittexture->refractcolor4f, refractcolor);
2679                         // make sure we do not gain energy even if surface colors are out of bounds
2680                         reflectcolor[0] = min(reflectcolor[0], 1.0f);
2681                         reflectcolor[1] = min(reflectcolor[1], 1.0f);
2682                         reflectcolor[2] = min(reflectcolor[2], 1.0f);
2683                         refractcolor[0] = min(refractcolor[0], 1.0f);
2684                         refractcolor[1] = min(refractcolor[1], 1.0f);
2685                         refractcolor[2] = min(refractcolor[2], 1.0f);
2686                 }
2687                 // reflected and refracted shots
2688                 VectorScale(reflectcolor, r_shadow_bouncegrid_state.settings.particlebounceintensity * reflectamount, reflectcolor);
2689                 VectorScale(refractcolor, (1.0f - reflectamount), refractcolor);
2690                 VectorMultiply(reflectcolor, shotcolor, reflectcolor);
2691                 VectorMultiply(refractcolor, shotcolor, refractcolor);
2692
2693                 if (VectorLength2(reflectcolor) >= bounceminimumintensity2)
2694                 {
2695                         // reflect the remaining portion of the line across plane normal
2696                         VectorSubtract(shotend, shothit, reflectend);
2697                         VectorReflect(reflectend, 1.0, surfacenormal, reflectend);
2698                         // calculate the new line start and end
2699                         VectorCopy(shothit, reflectstart);
2700                         VectorAdd(reflectstart, reflectend, reflectend);
2701                         R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, reflectstart, reflectend, reflectcolor, bounceminimumintensity2, previousrefractiveindex);
2702                 }
2703
2704                 if (VectorLength2(refractcolor) >= bounceminimumintensity2)
2705                 {
2706                         // Check what refractive index is on the other side
2707                         float refractiveindex;
2708                         VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2709                         refractiveindex = R_Shadow_BounceGrid_RefractiveIndexAtPoint(refractstart);
2710                         // reflect the remaining portion of the line across plane normal
2711                         VectorSubtract(shotend, shothit, refractend);
2712                         s = refractiveindex / previousrefractiveindex;
2713                         VectorReflect(refractend, -1.0f / s, surfacenormal, refractend);
2714                         // we also need to reflect the start to the other side of the plane so it doesn't just hit the same surface again
2715                         // calculate the new line start and end
2716                         VectorMA(shothit, 0.0625f, cliptrace.plane.normal, refractstart);
2717                         VectorAdd(refractstart, refractend, refractend);
2718                         R_Shadow_BounceGrid_TracePhotons_Shot(p, remainingbounces - 1, refractstart, refractend, refractcolor, bounceminimumintensity2, refractiveindex);
2719                 }
2720         }
2721 }
2722
2723 static void R_Shadow_BounceGrid_TracePhotons_ShotTask(taskqueue_task_t *t)
2724 {
2725         r_shadow_bouncegrid_photon_t *p = (r_shadow_bouncegrid_photon_t *)t->p[0];
2726         R_Shadow_BounceGrid_TracePhotons_Shot(p, r_shadow_bouncegrid_state.settings.maxbounce, p->start, p->end, p->color, p->bounceminimumintensity2, p->startrefractiveindex);
2727         t->done = 1;
2728 }
2729
2730 static void R_Shadow_BounceGrid_EnqueuePhotons_Task(taskqueue_task_t *t)
2731 {
2732         int i;
2733         for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2734                 TaskQueue_Setup(r_shadow_bouncegrid_state.photons_tasks + i, NULL, R_Shadow_BounceGrid_TracePhotons_ShotTask, 0, 0, r_shadow_bouncegrid_state.photons + i, NULL);
2735         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);
2736         if (r_shadow_bouncegrid_threaded.integer)
2737         {
2738                 TaskQueue_Enqueue(r_shadow_bouncegrid_state.numphotons, r_shadow_bouncegrid_state.photons_tasks);
2739                 TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.photons_done_task);
2740         }
2741         else
2742         {
2743                 // when not threaded we still have to report task status
2744                 for (i = 0; i < r_shadow_bouncegrid_state.numphotons; i++)
2745                         r_shadow_bouncegrid_state.photons_tasks[i].func(r_shadow_bouncegrid_state.photons_tasks + i);
2746                 r_shadow_bouncegrid_state.photons_done_task.done = 1;
2747         }
2748         t->done = 1;
2749 }
2750
2751 void R_Shadow_UpdateBounceGridTexture(void)
2752 {
2753         int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2754         r_shadow_bouncegrid_settings_t settings;
2755         qboolean enable = false;
2756         qboolean settingschanged;
2757
2758         enable = R_Shadow_BounceGrid_CheckEnable(flag);
2759         
2760         R_Shadow_BounceGrid_GenerateSettings(&settings);
2761         
2762         // changing intensity does not require an update
2763         r_shadow_bouncegrid_state.intensity = r_shadow_bouncegrid_intensity.value;
2764
2765         settingschanged = memcmp(&r_shadow_bouncegrid_state.settings, &settings, sizeof(settings)) != 0;
2766
2767         // when settings change, we free everything as it is just simpler that way.
2768         if (settingschanged || !enable)
2769         {
2770                 // not enabled, make sure we free anything we don't need anymore.
2771                 if (r_shadow_bouncegrid_state.texture)
2772                 {
2773                         R_FreeTexture(r_shadow_bouncegrid_state.texture);
2774                         r_shadow_bouncegrid_state.texture = NULL;
2775                 }
2776                 r_shadow_bouncegrid_state.highpixels = NULL;
2777                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2778                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2779                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2780                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2781                 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2782                 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2783                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2784                 r_shadow_bouncegrid_state.numpixels = 0;
2785                 r_shadow_bouncegrid_state.numphotons = 0;
2786                 r_shadow_bouncegrid_state.directional = false;
2787
2788                 if (!enable)
2789                         return;
2790         }
2791
2792         // if all the settings seem identical to the previous update, return
2793         if (r_shadow_bouncegrid_state.texture && (settings.staticmode || realtime < r_shadow_bouncegrid_state.lastupdatetime + r_shadow_bouncegrid_dynamic_updateinterval.value) && !settingschanged)
2794                 return;
2795
2796         // store the new settings
2797         r_shadow_bouncegrid_state.settings = settings;
2798
2799         R_Shadow_BounceGrid_UpdateSpacing();
2800
2801         // allocate the highpixels array we'll be accumulating light into
2802         if (r_shadow_bouncegrid_state.blurpixels[0] == NULL)
2803                 r_shadow_bouncegrid_state.blurpixels[0] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2804         if (r_shadow_bouncegrid_state.settings.blur && r_shadow_bouncegrid_state.blurpixels[1] == NULL)
2805                 r_shadow_bouncegrid_state.blurpixels[1] = (float *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.numpixels * sizeof(float[4]));
2806         r_shadow_bouncegrid_state.highpixels_index = 0;
2807         r_shadow_bouncegrid_state.highpixels = r_shadow_bouncegrid_state.blurpixels[r_shadow_bouncegrid_state.highpixels_index];
2808
2809         // set up the tracking of photon data
2810         if (r_shadow_bouncegrid_state.photons == NULL)
2811                 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));
2812         if (r_shadow_bouncegrid_state.photons_tasks == NULL)
2813                 r_shadow_bouncegrid_state.photons_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2814         r_shadow_bouncegrid_state.numphotons = 0;
2815
2816         // set up the tracking of slice tasks
2817         if (r_shadow_bouncegrid_state.slices_tasks == NULL)
2818                 r_shadow_bouncegrid_state.slices_tasks = (taskqueue_task_t *)Mem_Alloc(r_main_mempool, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2819
2820         memset(&r_shadow_bouncegrid_state.cleartex_task, 0, sizeof(taskqueue_task_t));
2821         memset(&r_shadow_bouncegrid_state.assignphotons_task, 0, sizeof(taskqueue_task_t));
2822         memset(&r_shadow_bouncegrid_state.enqueuephotons_task, 0, sizeof(taskqueue_task_t));
2823         memset(r_shadow_bouncegrid_state.photons_tasks, 0, r_shadow_bouncegrid_state.settings.maxphotons * sizeof(taskqueue_task_t));
2824         memset(&r_shadow_bouncegrid_state.photons_done_task, 0, sizeof(taskqueue_task_t));
2825         memset(&r_shadow_bouncegrid_state.enqueue_slices_task, 0, sizeof(taskqueue_task_t));
2826         memset(r_shadow_bouncegrid_state.slices_tasks, 0, r_shadow_bouncegrid_state.resolution[2] * sizeof(taskqueue_task_t));
2827         memset(&r_shadow_bouncegrid_state.slices_done_task, 0, sizeof(taskqueue_task_t));
2828         memset(&r_shadow_bouncegrid_state.blurpixels_task, 0, sizeof(taskqueue_task_t));
2829
2830         // clear the texture
2831         TaskQueue_Setup(&r_shadow_bouncegrid_state.cleartex_task, NULL, R_Shadow_BounceGrid_ClearTex_Task, 0, 0, NULL, NULL);
2832         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.cleartex_task);
2833
2834         // calculate weighting factors for distributing photons among the lights
2835         TaskQueue_Setup(&r_shadow_bouncegrid_state.assignphotons_task, NULL, R_Shadow_BounceGrid_AssignPhotons_Task, 0, 0, NULL, NULL);
2836         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.assignphotons_task);
2837
2838         // enqueue tasks to trace the photons from lights
2839         TaskQueue_Setup(&r_shadow_bouncegrid_state.enqueuephotons_task, &r_shadow_bouncegrid_state.assignphotons_task, R_Shadow_BounceGrid_EnqueuePhotons_Task, 0, 0, NULL, NULL);
2840         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueuephotons_task);
2841
2842         // accumulate the light paths into texture
2843         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);
2844         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.enqueue_slices_task);
2845
2846         // apply a mild blur filter to the texture
2847         TaskQueue_Setup(&r_shadow_bouncegrid_state.blurpixels_task, &r_shadow_bouncegrid_state.slices_done_task, R_Shadow_BounceGrid_BlurPixels_Task, 0, 0, NULL, NULL);
2848         TaskQueue_Enqueue(1, &r_shadow_bouncegrid_state.blurpixels_task);
2849
2850         TaskQueue_WaitForTaskDone(&r_shadow_bouncegrid_state.blurpixels_task);
2851         R_TimeReport("bouncegrid_gen");
2852
2853         // convert the pixels to lower precision and upload the texture
2854         // this unfortunately has to run on the main thread for OpenGL calls, so we have to block on the previous task...
2855         R_Shadow_BounceGrid_ConvertPixelsAndUpload();
2856         R_TimeReport("bouncegrid_tex");
2857
2858         // after we compute the static lighting we don't need to keep the highpixels array around
2859         if (settings.staticmode)
2860         {
2861                 r_shadow_bouncegrid_state.highpixels = NULL;
2862                 if (r_shadow_bouncegrid_state.blurpixels[0]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[0]); r_shadow_bouncegrid_state.blurpixels[0] = NULL;
2863                 if (r_shadow_bouncegrid_state.blurpixels[1]) Mem_Free(r_shadow_bouncegrid_state.blurpixels[1]); r_shadow_bouncegrid_state.blurpixels[1] = NULL;
2864                 if (r_shadow_bouncegrid_state.u8pixels) Mem_Free(r_shadow_bouncegrid_state.u8pixels); r_shadow_bouncegrid_state.u8pixels = NULL;
2865                 if (r_shadow_bouncegrid_state.fp16pixels) Mem_Free(r_shadow_bouncegrid_state.fp16pixels); r_shadow_bouncegrid_state.fp16pixels = NULL;
2866                 if (r_shadow_bouncegrid_state.photons) Mem_Free(r_shadow_bouncegrid_state.photons); r_shadow_bouncegrid_state.photons = NULL;
2867                 if (r_shadow_bouncegrid_state.photons_tasks) Mem_Free(r_shadow_bouncegrid_state.photons_tasks); r_shadow_bouncegrid_state.photons_tasks = NULL;
2868                 if (r_shadow_bouncegrid_state.slices_tasks) Mem_Free(r_shadow_bouncegrid_state.slices_tasks); r_shadow_bouncegrid_state.slices_tasks = NULL;
2869         }
2870 }
2871
2872 void R_Shadow_RenderMode_VisibleLighting(qboolean transparent)
2873 {
2874         R_Shadow_RenderMode_Reset();
2875         GL_BlendFunc(GL_ONE, GL_ONE);
2876         GL_DepthRange(0, 1);
2877         GL_DepthTest(r_showlighting.integer < 2);
2878         GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2879         if (!transparent)
2880                 GL_DepthFunc(GL_EQUAL);
2881         r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2882 }
2883
2884 void R_Shadow_RenderMode_End(void)
2885 {
2886         R_Shadow_RenderMode_Reset();
2887         R_Shadow_RenderMode_ActiveLight(NULL);
2888         GL_DepthMask(true);
2889         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2890         r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2891 }
2892
2893 int bboxedges[12][2] =
2894 {
2895         // top
2896         {0, 1}, // +X
2897         {0, 2}, // +Y
2898         {1, 3}, // Y, +X
2899         {2, 3}, // X, +Y
2900         // bottom
2901         {4, 5}, // +X
2902         {4, 6}, // +Y
2903         {5, 7}, // Y, +X
2904         {6, 7}, // X, +Y
2905         // verticals
2906         {0, 4}, // +Z
2907         {1, 5}, // X, +Z
2908         {2, 6}, // Y, +Z
2909         {3, 7}, // XY, +Z
2910 };
2911
2912 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2913 {
2914         if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2915         {
2916                 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2917                 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2918                 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2919                 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2920                 return false;
2921         }
2922         if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2923                 return true; // invisible
2924         if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2925         || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2926         || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2927         || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2928                 r_refdef.stats[r_stat_lights_scissored]++;
2929         return false;
2930 }
2931
2932 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2933 {
2934         // used to display how many times a surface is lit for level design purposes
2935         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2936         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2937         RSurf_DrawBatch();
2938 }
2939
2940 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])
2941 {
2942         // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2943         R_SetupShader_Surface(ambientcolor, diffusecolor, specularcolor, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
2944         RSurf_DrawBatch();
2945 }
2946
2947 extern cvar_t gl_lightmaps;
2948 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2949 {
2950         qboolean negated;
2951         float ambientcolor[3], diffusecolor[3], specularcolor[3];
2952         VectorM(rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient, rsurface.texture->render_rtlight_diffuse, ambientcolor);
2953         VectorM(rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient), rsurface.texture->render_rtlight_diffuse, diffusecolor);
2954         VectorM(rsurface.rtlight->specularscale, rsurface.texture->render_rtlight_specular, specularcolor);
2955         if (!r_shadow_usenormalmap.integer)
2956         {
2957                 VectorMAM(1.0f, ambientcolor, 1.0f, diffusecolor, ambientcolor);
2958                 VectorClear(diffusecolor);
2959                 VectorClear(specularcolor);
2960         }
2961         VectorMultiply(ambientcolor, rsurface.rtlight->currentcolor, ambientcolor);
2962         VectorMultiply(diffusecolor, rsurface.rtlight->currentcolor, diffusecolor);
2963         VectorMultiply(specularcolor, rsurface.rtlight->currentcolor, specularcolor);
2964         if (VectorLength2(ambientcolor) + VectorLength2(diffusecolor) + VectorLength2(specularcolor) < (1.0f / 1048576.0f))
2965                 return;
2966         negated = (rsurface.rtlight->currentcolor[0] + rsurface.rtlight->currentcolor[1] + rsurface.rtlight->currentcolor[2] < 0);
2967         if(negated)
2968         {
2969                 VectorNegate(ambientcolor, ambientcolor);
2970                 VectorNegate(diffusecolor, diffusecolor);
2971                 VectorNegate(specularcolor, specularcolor);
2972                 GL_BlendEquationSubtract(true);
2973         }
2974         RSurf_SetupDepthAndCulling();
2975         switch (r_shadow_rendermode)
2976         {
2977         case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2978                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2979                 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2980                 break;
2981         case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2982                 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, ambientcolor, diffusecolor, specularcolor);
2983                 break;
2984         default:
2985                 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2986                 break;
2987         }
2988         if(negated)
2989                 GL_BlendEquationSubtract(false);
2990 }
2991
2992 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)
2993 {
2994         matrix4x4_t tempmatrix = *matrix;
2995         Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2996
2997         // if this light has been compiled before, free the associated data
2998         R_RTLight_Uncompile(rtlight);
2999
3000         // clear it completely to avoid any lingering data
3001         memset(rtlight, 0, sizeof(*rtlight));
3002
3003         // copy the properties
3004         rtlight->matrix_lighttoworld = tempmatrix;
3005         Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3006         Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3007         rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3008         VectorCopy(color, rtlight->color);
3009         rtlight->cubemapname[0] = 0;
3010         if (cubemapname && cubemapname[0])
3011                 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3012         rtlight->shadow = shadow;
3013         rtlight->corona = corona;
3014         rtlight->style = style;
3015         rtlight->isstatic = isstatic;
3016         rtlight->coronasizescale = coronasizescale;
3017         rtlight->ambientscale = ambientscale;
3018         rtlight->diffusescale = diffusescale;
3019         rtlight->specularscale = specularscale;
3020         rtlight->flags = flags;
3021
3022         // compute derived data
3023         //rtlight->cullradius = rtlight->radius;
3024         //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3025         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3026         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3027         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3028         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3029         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3030         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3031 }
3032
3033 // compiles rtlight geometry
3034 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3035 void R_RTLight_Compile(rtlight_t *rtlight)
3036 {
3037         int i;
3038         int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3039         int lighttris, shadowtris;
3040         entity_render_t *ent = r_refdef.scene.worldentity;
3041         dp_model_t *model = r_refdef.scene.worldmodel;
3042         unsigned char *data;
3043
3044         // compile the light
3045         rtlight->compiled = true;
3046         rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3047         rtlight->static_numleafs = 0;
3048         rtlight->static_numleafpvsbytes = 0;
3049         rtlight->static_leaflist = NULL;
3050         rtlight->static_leafpvs = NULL;
3051         rtlight->static_numsurfaces = 0;
3052         rtlight->static_surfacelist = NULL;
3053         rtlight->static_shadowmap_receivers = 0x3F;
3054         rtlight->static_shadowmap_casters = 0x3F;
3055         rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3056         rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3057         rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3058         rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3059         rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3060         rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3061
3062         if (model && model->GetLightInfo)
3063         {
3064                 // this variable must be set for the CompileShadowMap code
3065                 r_shadow_compilingrtlight = rtlight;
3066                 R_FrameData_SetMark();
3067                 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);
3068                 R_FrameData_ReturnToMark();
3069                 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3070                 numshadowtrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3071                 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3072                 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3073                 rtlight->static_numsurfaces = numsurfaces;
3074                 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3075                 rtlight->static_numleafs = numleafs;
3076                 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3077                 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3078                 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3079                 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3080                 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3081                 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3082                 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3083                 if (rtlight->static_numsurfaces)
3084                         memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3085                 if (rtlight->static_numleafs)
3086                         memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3087                 if (rtlight->static_numleafpvsbytes)
3088                         memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3089                 if (rtlight->static_numshadowtrispvsbytes)
3090                         memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3091                 if (rtlight->static_numlighttrispvsbytes)
3092                         memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3093                 R_FrameData_SetMark();
3094                 if (model->CompileShadowMap && rtlight->shadow)
3095                         model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3096                 R_FrameData_ReturnToMark();
3097                 // now we're done compiling the rtlight
3098                 r_shadow_compilingrtlight = NULL;
3099         }
3100
3101
3102         // use smallest available cullradius - box radius or light radius
3103         //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3104         //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3105
3106         lighttris = 0;
3107         if (rtlight->static_numlighttrispvsbytes)
3108                 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3109                         if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3110                                 lighttris++;
3111
3112         shadowtris = 0;
3113         if (rtlight->static_numshadowtrispvsbytes)
3114                 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3115                         if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3116                                 shadowtris++;
3117
3118         if (developer_extra.integer)
3119                 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);
3120 }
3121
3122 void R_RTLight_Uncompile(rtlight_t *rtlight)
3123 {
3124         if (rtlight->compiled)
3125         {
3126                 if (rtlight->static_meshchain_shadow_shadowmap)
3127                         Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3128                 rtlight->static_meshchain_shadow_shadowmap = NULL;
3129                 // these allocations are grouped
3130                 if (rtlight->static_surfacelist)
3131                         Mem_Free(rtlight->static_surfacelist);
3132                 rtlight->static_numleafs = 0;
3133                 rtlight->static_numleafpvsbytes = 0;
3134                 rtlight->static_leaflist = NULL;
3135                 rtlight->static_leafpvs = NULL;
3136                 rtlight->static_numsurfaces = 0;
3137                 rtlight->static_surfacelist = NULL;
3138                 rtlight->static_numshadowtrispvsbytes = 0;
3139                 rtlight->static_shadowtrispvs = NULL;
3140                 rtlight->static_numlighttrispvsbytes = 0;
3141                 rtlight->static_lighttrispvs = NULL;
3142                 rtlight->compiled = false;
3143         }
3144 }
3145
3146 void R_Shadow_UncompileWorldLights(void)
3147 {
3148         size_t lightindex;
3149         dlight_t *light;
3150         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3151         for (lightindex = 0;lightindex < range;lightindex++)
3152         {
3153                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3154                 if (!light)
3155                         continue;
3156                 R_RTLight_Uncompile(&light->rtlight);
3157         }
3158 }
3159
3160 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3161 {
3162         int i, j;
3163         mplane_t plane;
3164         // reset the count of frustum planes
3165         // see rtlight->cached_frustumplanes definition for how much this array
3166         // can hold
3167         rtlight->cached_numfrustumplanes = 0;
3168
3169         if (r_trippy.integer)
3170                 return;
3171
3172         // haven't implemented a culling path for ortho rendering
3173         if (!r_refdef.view.useperspective)
3174         {
3175                 // check if the light is on screen and copy the 4 planes if it is
3176                 for (i = 0;i < 4;i++)
3177                         if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3178                                 break;
3179                 if (i == 4)
3180                         for (i = 0;i < 4;i++)
3181                                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3182                 return;
3183         }
3184
3185 #if 1
3186         // generate a deformed frustum that includes the light origin, this is
3187         // used to cull shadow casting surfaces that can not possibly cast a
3188         // shadow onto the visible light-receiving surfaces, which can be a
3189         // performance gain
3190         //
3191         // if the light origin is onscreen the result will be 4 planes exactly
3192         // if the light origin is offscreen on only one axis the result will
3193         // be exactly 5 planes (split-side case)
3194         // if the light origin is offscreen on two axes the result will be
3195         // exactly 4 planes (stretched corner case)
3196         for (i = 0;i < 4;i++)
3197         {
3198                 // quickly reject standard frustum planes that put the light
3199                 // origin outside the frustum
3200                 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3201                         continue;
3202                 // copy the plane
3203                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3204         }
3205         // if all the standard frustum planes were accepted, the light is onscreen
3206         // otherwise we need to generate some more planes below...
3207         if (rtlight->cached_numfrustumplanes < 4)
3208         {
3209                 // at least one of the stock frustum planes failed, so we need to
3210                 // create one or two custom planes to enclose the light origin
3211                 for (i = 0;i < 4;i++)
3212                 {
3213                         // create a plane using the view origin and light origin, and a
3214                         // single point from the frustum corner set
3215                         TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3216                         VectorNormalize(plane.normal);
3217                         plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3218                         // see if this plane is backwards and flip it if so
3219                         for (j = 0;j < 4;j++)
3220                                 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3221                                         break;
3222                         if (j < 4)
3223                         {
3224                                 VectorNegate(plane.normal, plane.normal);
3225                                 plane.dist *= -1;
3226                                 // flipped plane, test again to see if it is now valid
3227                                 for (j = 0;j < 4;j++)
3228                                         if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3229                                                 break;
3230                                 // if the plane is still not valid, then it is dividing the
3231                                 // frustum and has to be rejected
3232                                 if (j < 4)
3233                                         continue;
3234                         }
3235                         // we have created a valid plane, compute extra info
3236                         PlaneClassify(&plane);
3237                         // copy the plane
3238                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3239 #if 1
3240                         // if we've found 5 frustum planes then we have constructed a
3241                         // proper split-side case and do not need to keep searching for
3242                         // planes to enclose the light origin
3243                         if (rtlight->cached_numfrustumplanes == 5)
3244                                 break;
3245 #endif
3246                 }
3247         }
3248 #endif
3249
3250 #if 0
3251         for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3252         {
3253                 plane = rtlight->cached_frustumplanes[i];
3254                 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));
3255         }
3256 #endif
3257
3258 #if 0
3259         // now add the light-space box planes if the light box is rotated, as any
3260         // caster outside the oriented light box is irrelevant (even if it passed
3261         // the worldspace light box, which is axial)
3262         if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3263         {
3264                 for (i = 0;i < 6;i++)
3265                 {
3266                         vec3_t v;
3267                         VectorClear(v);
3268                         v[i >> 1] = (i & 1) ? -1 : 1;
3269                         Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3270                         VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3271                         plane.dist = VectorNormalizeLength(plane.normal);
3272                         plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3273                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3274                 }
3275         }
3276 #endif
3277
3278 #if 0
3279         // add the world-space reduced box planes
3280         for (i = 0;i < 6;i++)
3281         {
3282                 VectorClear(plane.normal);
3283                 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3284                 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3285                 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3286         }
3287 #endif
3288
3289 #if 0
3290         {
3291         int j, oldnum;
3292         vec3_t points[8];
3293         vec_t bestdist;
3294         // reduce all plane distances to tightly fit the rtlight cull box, which
3295         // is in worldspace
3296         VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3297         VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3298         VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3299         VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3300         VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3301         VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3302         VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3303         VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3304         oldnum = rtlight->cached_numfrustumplanes;
3305         rtlight->cached_numfrustumplanes = 0;
3306         for (j = 0;j < oldnum;j++)
3307         {
3308                 // find the nearest point on the box to this plane
3309                 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3310                 for (i = 1;i < 8;i++)
3311                 {
3312                         dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3313                         if (bestdist > dist)
3314                                 bestdist = dist;
3315                 }
3316                 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);
3317                 // if the nearest point is near or behind the plane, we want this
3318                 // plane, otherwise the plane is useless as it won't cull anything
3319                 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3320                 {
3321                         PlaneClassify(&rtlight->cached_frustumplanes[j]);
3322                         rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3323                 }
3324         }
3325         }
3326 #endif
3327 }
3328
3329 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3330 {
3331         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3332
3333         if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3334         {
3335                 shadowmesh_t *mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3336                 if (mesh->sidetotals[r_shadow_shadowmapside])
3337                 {
3338                         CHECKGLERROR
3339                         GL_CullFace(GL_NONE);
3340                         r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3341                         R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3342                         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);
3343                         CHECKGLERROR
3344                 }
3345         }
3346         else if (r_refdef.scene.worldentity->model)
3347                 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);
3348
3349         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3350 }
3351
3352 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3353 {
3354         vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3355         vec_t relativeshadowradius;
3356         RSurf_ActiveModelEntity(ent, false, false, false);
3357         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3358         // we need to re-init the shader for each entity because the matrix changed
3359         relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3360         relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3361         relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3362         relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3363         relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3364         relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3365         relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3366         ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3367         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3368 }
3369
3370 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3371 {
3372         // set up properties for rendering light onto this entity
3373         RSurf_ActiveModelEntity(ent, true, true, false);
3374         Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3375         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3376         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3377         Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3378 }
3379
3380 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3381 {
3382         if (!r_refdef.scene.worldmodel->DrawLight)
3383                 return;
3384
3385         // set up properties for rendering light onto this entity
3386         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
3387         rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3388         Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3389         Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3390         VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3391
3392         r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3393
3394         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3395 }
3396
3397 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3398 {
3399         dp_model_t *model = ent->model;
3400         if (!model->DrawLight)
3401                 return;
3402
3403         R_Shadow_SetupEntityLight(ent);
3404
3405         model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3406
3407         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
3408 }
3409
3410 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3411 {
3412         int i;
3413         float f;
3414         int numleafs, numsurfaces;
3415         int *leaflist, *surfacelist;
3416         unsigned char *leafpvs;
3417         unsigned char *shadowtrispvs;
3418         unsigned char *lighttrispvs;
3419         //unsigned char *surfacesides;
3420         int numlightentities;
3421         int numlightentities_noselfshadow;
3422         int numshadowentities;
3423         int numshadowentities_noselfshadow;
3424         // FIXME: bounds check lightentities and shadowentities, etc.
3425         static entity_render_t *lightentities[MAX_EDICTS];
3426         static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3427         static entity_render_t *shadowentities[MAX_EDICTS];
3428         static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3429         qboolean nolight;
3430         qboolean castshadows;
3431
3432         rtlight->draw = false;
3433         rtlight->cached_numlightentities = 0;
3434         rtlight->cached_numlightentities_noselfshadow = 0;
3435         rtlight->cached_numshadowentities = 0;
3436         rtlight->cached_numshadowentities_noselfshadow = 0;
3437         rtlight->cached_numsurfaces = 0;
3438         rtlight->cached_lightentities = NULL;
3439         rtlight->cached_lightentities_noselfshadow = NULL;
3440         rtlight->cached_shadowentities = NULL;
3441         rtlight->cached_shadowentities_noselfshadow = NULL;
3442         rtlight->cached_shadowtrispvs = NULL;
3443         rtlight->cached_lighttrispvs = NULL;
3444         rtlight->cached_surfacelist = NULL;
3445         rtlight->shadowmapsidesize = 0;
3446
3447         // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3448         // skip lights that are basically invisible (color 0 0 0)
3449         nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3450
3451         // loading is done before visibility checks because loading should happen
3452         // all at once at the start of a level, not when it stalls gameplay.
3453         // (especially important to benchmarks)
3454         // compile light
3455         if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3456         {
3457                 if (rtlight->compiled)
3458                         R_RTLight_Uncompile(rtlight);
3459                 R_RTLight_Compile(rtlight);
3460         }
3461
3462         // load cubemap
3463         rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3464
3465         // look up the light style value at this time
3466         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3467         VectorScale(rtlight->color, f, rtlight->currentcolor);
3468         /*
3469         if (rtlight->selected)
3470         {
3471                 f = 2 + sin(realtime * M_PI * 4.0);
3472                 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3473         }
3474         */
3475
3476         // skip if lightstyle is currently off
3477         if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3478                 return;
3479
3480         // skip processing on corona-only lights
3481         if (nolight)
3482                 return;
3483
3484         // skip if the light box is not touching any visible leafs
3485         if (r_shadow_culllights_pvs.integer
3486                 && r_refdef.scene.worldmodel
3487                 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
3488                 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, rtlight->cullmins, rtlight->cullmaxs))
3489                 return;
3490
3491         // skip if the light box is not visible to traceline
3492         if (r_shadow_culllights_trace.integer)
3493         {
3494                 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))
3495                         rtlight->trace_timer = realtime;
3496                 if (realtime - rtlight->trace_timer > r_shadow_culllights_trace_delay.value)
3497                         return;
3498         }
3499
3500         // skip if the light box is off screen
3501         if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3502                 return;
3503
3504         // in the typical case this will be quickly replaced by GetLightInfo
3505         VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3506         VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3507
3508         R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3509
3510         // 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
3511         if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
3512                 return;
3513
3514         if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3515         {
3516                 // compiled light, world available and can receive realtime lighting
3517                 // retrieve leaf information
3518                 numleafs = rtlight->static_numleafs;
3519                 leaflist = rtlight->static_leaflist;
3520                 leafpvs = rtlight->static_leafpvs;
3521                 numsurfaces = rtlight->static_numsurfaces;
3522                 surfacelist = rtlight->static_surfacelist;
3523                 //surfacesides = NULL;
3524                 shadowtrispvs = rtlight->static_shadowtrispvs;
3525                 lighttrispvs = rtlight->static_lighttrispvs;
3526         }
3527         else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3528         {
3529                 // dynamic light, world available and can receive realtime lighting
3530                 // calculate lit surfaces and leafs
3531                 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);
3532                 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3533                 leaflist = r_shadow_buffer_leaflist;
3534                 leafpvs = r_shadow_buffer_leafpvs;
3535                 surfacelist = r_shadow_buffer_surfacelist;
3536                 //surfacesides = r_shadow_buffer_surfacesides;
3537                 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3538                 lighttrispvs = r_shadow_buffer_lighttrispvs;
3539                 // if the reduced leaf bounds are offscreen, skip it
3540                 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3541                         return;
3542         }
3543         else
3544         {
3545                 // no world
3546                 numleafs = 0;
3547                 leaflist = NULL;
3548                 leafpvs = NULL;
3549                 numsurfaces = 0;
3550                 surfacelist = NULL;
3551                 //surfacesides = NULL;
3552                 shadowtrispvs = NULL;
3553                 lighttrispvs = NULL;
3554         }
3555         // check if light is illuminating any visible leafs
3556         if (numleafs)
3557         {
3558                 for (i = 0; i < numleafs; i++)
3559                         if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3560                                 break;
3561                 if (i == numleafs)
3562                         return;
3563         }
3564
3565         // make a list of lit entities and shadow casting entities
3566         numlightentities = 0;
3567         numlightentities_noselfshadow = 0;
3568         numshadowentities = 0;
3569         numshadowentities_noselfshadow = 0;
3570
3571         // add dynamic entities that are lit by the light
3572         for (i = 0; i < r_refdef.scene.numentities; i++)
3573         {
3574                 dp_model_t *model;
3575                 entity_render_t *ent = r_refdef.scene.entities[i];
3576                 vec3_t org;
3577                 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3578                         continue;
3579                 // skip the object entirely if it is not within the valid
3580                 // shadow-casting region (which includes the lit region)
3581                 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3582                         continue;
3583                 if (!(model = ent->model))
3584                         continue;
3585                 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3586                 {
3587                         // this entity wants to receive light, is visible, and is
3588                         // inside the light box
3589                         // TODO: check if the surfaces in the model can receive light
3590                         // so now check if it's in a leaf seen by the light
3591                         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))
3592                                 continue;
3593                         if (ent->flags & RENDER_NOSELFSHADOW)
3594                                 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3595                         else
3596                                 lightentities[numlightentities++] = ent;
3597                         // since it is lit, it probably also casts a shadow...
3598                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3599                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3600                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3601                         {
3602                                 // note: exterior models without the RENDER_NOSELFSHADOW
3603                                 // flag still create a RENDER_NOSELFSHADOW shadow but
3604                                 // are lit normally, this means that they are
3605                                 // self-shadowing but do not shadow other
3606                                 // RENDER_NOSELFSHADOW entities such as the gun
3607                                 // (very weird, but keeps the player shadow off the gun)
3608                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3609                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3610                                 else
3611                                         shadowentities[numshadowentities++] = ent;
3612                         }
3613                 }
3614                 else if (ent->flags & RENDER_SHADOW)
3615                 {
3616                         // this entity is not receiving light, but may still need to
3617                         // cast a shadow...
3618                         // TODO: check if the surfaces in the model can cast shadow
3619                         // now check if it is in a leaf seen by the light
3620                         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))
3621                                 continue;
3622                         // about the VectorDistance2 - light emitting entities should not cast their own shadow
3623                         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3624                         if ((ent->flags & RENDER_SHADOW) && model->DrawShadowMap && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3625                         {
3626                                 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3627                                         shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3628                                 else
3629                                         shadowentities[numshadowentities++] = ent;
3630                         }
3631                 }
3632         }
3633
3634         // return if there's nothing at all to light
3635         if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3636                 return;
3637
3638         // count this light in the r_speeds
3639         r_refdef.stats[r_stat_lights]++;
3640
3641         // flag it as worth drawing later
3642         rtlight->draw = true;
3643
3644         // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
3645         castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3646         if (!castshadows)
3647                 numshadowentities = numshadowentities_noselfshadow = 0;
3648         rtlight->castshadows = castshadows;
3649
3650         // cache all the animated entities that cast a shadow but are not visible
3651         for (i = 0; i < numshadowentities; i++)
3652                 R_AnimCache_GetEntity(shadowentities[i], false, false);
3653         for (i = 0; i < numshadowentities_noselfshadow; i++)
3654                 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3655
3656         // 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)
3657         if (numshadowentities_noselfshadow > 0 && (numlightentities_noselfshadow == 0 || r_shadow_usingdeferredprepass))
3658         {
3659                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3660                         shadowentities[numshadowentities++] = shadowentities_noselfshadow[i];
3661                 numshadowentities_noselfshadow = 0;
3662         }
3663
3664         // we can convert noselfshadow to regular if there are no casters of that type
3665         if (numlightentities_noselfshadow > 0 && numshadowentities_noselfshadow == 0)
3666         {
3667                 for (i = 0; i < numlightentities_noselfshadow; i++)
3668                         lightentities[numlightentities++] = lightentities_noselfshadow[i];
3669                 numlightentities_noselfshadow = 0;
3670         }
3671
3672         // allocate some temporary memory for rendering this light later in the frame
3673         // reusable buffers need to be copied, static data can be used as-is
3674         rtlight->cached_numlightentities               = numlightentities;
3675         rtlight->cached_numlightentities_noselfshadow  = numlightentities_noselfshadow;
3676         rtlight->cached_numshadowentities              = numshadowentities;
3677         rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3678         rtlight->cached_numsurfaces                    = numsurfaces;
3679         rtlight->cached_lightentities                  = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3680         rtlight->cached_lightentities_noselfshadow     = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3681         rtlight->cached_shadowentities                 = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3682         rtlight->cached_shadowentities_noselfshadow    = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3683         if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3684         {
3685                 int numshadowtrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3686                 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3687                 rtlight->cached_shadowtrispvs                  =   (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3688                 rtlight->cached_lighttrispvs                   =   (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3689                 rtlight->cached_surfacelist                    =              (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3690         }
3691         else
3692         {
3693                 // compiled light data
3694                 rtlight->cached_shadowtrispvs = shadowtrispvs;
3695                 rtlight->cached_lighttrispvs = lighttrispvs;
3696                 rtlight->cached_surfacelist = surfacelist;
3697         }
3698
3699         if (R_Shadow_ShadowMappingEnabled())
3700         {
3701                 // figure out the shadowmapping parameters for this light
3702                 vec3_t nearestpoint;
3703                 vec_t distance;
3704                 int lodlinear;
3705                 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3706                 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3707                 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3708                 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3709                 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / rtlight->radius));
3710                 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3711                 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3712                 rtlight->shadowmapsidesize = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3713                 // shadowmapatlas* variables will be set by R_Shadow_PrepareLights()
3714         }
3715 }
3716
3717 static void R_Shadow_DrawLightShadowMaps(rtlight_t *rtlight)
3718 {
3719         int i;
3720         int numsurfaces;
3721         unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3722         int numlightentities;
3723         int numlightentities_noselfshadow;
3724         int numshadowentities;
3725         int numshadowentities_noselfshadow;
3726         entity_render_t **lightentities;
3727         entity_render_t **lightentities_noselfshadow;
3728         entity_render_t **shadowentities;
3729         entity_render_t **shadowentities_noselfshadow;
3730         int *surfacelist;
3731         static unsigned char entitysides[MAX_EDICTS];
3732         static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3733         float borderbias;
3734         int side;
3735         int size;
3736         int castermask;
3737         int receivermask;
3738         matrix4x4_t radiustolight;
3739
3740         // check if we cached this light this frame (meaning it is worth drawing)
3741         if (!rtlight->draw || !rtlight->castshadows)
3742                 return;
3743
3744         // if PrepareLights could not find any space for this shadowmap, we may as well mark it as not casting shadows...
3745         if (rtlight->shadowmapatlassidesize == 0)
3746         {
3747                 rtlight->castshadows = false;
3748                 return;
3749         }
3750
3751         // set up a scissor rectangle for this light
3752         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3753                 return;
3754
3755         // don't let sound skip if going slow
3756         if (r_refdef.scene.extraupdate)
3757                 S_ExtraUpdate();
3758
3759         numlightentities = rtlight->cached_numlightentities;
3760         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3761         numshadowentities = rtlight->cached_numshadowentities;
3762         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3763         numsurfaces = rtlight->cached_numsurfaces;
3764         lightentities = rtlight->cached_lightentities;
3765         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3766         shadowentities = rtlight->cached_shadowentities;
3767         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3768         shadowtrispvs = rtlight->cached_shadowtrispvs;
3769         lighttrispvs = rtlight->cached_lighttrispvs;
3770         surfacelist = rtlight->cached_surfacelist;
3771
3772         // make this the active rtlight for rendering purposes
3773         R_Shadow_RenderMode_ActiveLight(rtlight);
3774
3775         radiustolight = rtlight->matrix_worldtolight;
3776         Matrix4x4_Abs(&radiustolight);
3777
3778         size = rtlight->shadowmapatlassidesize;
3779         borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3780
3781         surfacesides = NULL;
3782         castermask = 0;
3783         receivermask = 0;
3784         if (numsurfaces)
3785         {
3786                 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3787                 {
3788                         castermask = rtlight->static_shadowmap_casters;
3789                         receivermask = rtlight->static_shadowmap_receivers;
3790                 }
3791                 else
3792                 {
3793                         surfacesides = r_shadow_buffer_surfacesides;
3794                         for (i = 0; i < numsurfaces; i++)
3795                         {
3796                                 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3797                                 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3798                                 castermask |= surfacesides[i];
3799                                 receivermask |= surfacesides[i];
3800                         }
3801                 }
3802         }
3803
3804         for (i = 0; i < numlightentities && receivermask < 0x3F; i++)
3805                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3806         for (i = 0; i < numlightentities_noselfshadow && receivermask < 0x3F; i++)
3807                 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3808
3809         receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3810
3811         if (receivermask)
3812         {
3813                 for (i = 0; i < numshadowentities; i++)
3814                         castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3815                 for (i = 0; i < numshadowentities_noselfshadow; i++)
3816                         castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3817         }
3818
3819         // there is no need to render shadows for sides that have no receivers...
3820         castermask &= receivermask;
3821
3822         //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3823
3824         // render shadow casters into shadowmaps for this light
3825         for (side = 0; side < 6; side++)
3826         {
3827                 int bit = 1 << side;
3828                 if (castermask & bit)
3829                 {
3830                         R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0], rtlight->shadowmapatlasposition[1]);
3831                         if (numsurfaces)
3832                                 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3833                         for (i = 0; i < numshadowentities; i++)
3834                                 if (entitysides[i] & bit)
3835                                         R_Shadow_DrawEntityShadow(shadowentities[i]);
3836                         for (i = 0; i < numshadowentities_noselfshadow; i++)
3837                                 if (entitysides_noselfshadow[i] & bit)
3838                                         R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3839                 }
3840         }
3841         // additionally if there are any noselfshadow casters we have to render a second set of shadowmaps without those :(
3842         if (numshadowentities_noselfshadow)
3843         {
3844                 for (side = 0; side < 6; side++)
3845                 {
3846                         int bit = 1 << side;
3847                         if (castermask & bit)
3848                         {
3849                                 R_Shadow_RenderMode_ShadowMap(side, size, rtlight->shadowmapatlasposition[0] + size * 2, rtlight->shadowmapatlasposition[1]);
3850                                 if (numsurfaces)
3851                                         R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3852                                 for (i = 0; i < numshadowentities; i++)
3853                                         if (entitysides[i] & bit)
3854                                                 R_Shadow_DrawEntityShadow(shadowentities[i]);
3855                         }
3856                 }
3857         }
3858 }
3859
3860 static void R_Shadow_DrawLight(rtlight_t *rtlight)
3861 {
3862         int i;
3863         int numsurfaces;
3864         unsigned char *shadowtrispvs, *lighttrispvs;
3865         int numlightentities;
3866         int numlightentities_noselfshadow;
3867         int numshadowentities;
3868         int numshadowentities_noselfshadow;
3869         entity_render_t **lightentities;
3870         entity_render_t **lightentities_noselfshadow;
3871         entity_render_t **shadowentities;
3872         entity_render_t **shadowentities_noselfshadow;
3873         int *surfacelist;
3874         qboolean castshadows;
3875
3876         // check if we cached this light this frame (meaning it is worth drawing)
3877         if (!rtlight->draw)
3878                 return;
3879
3880         // set up a scissor rectangle for this light
3881         if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3882                 return;
3883
3884         // don't let sound skip if going slow
3885         if (r_refdef.scene.extraupdate)
3886                 S_ExtraUpdate();
3887
3888         numlightentities = rtlight->cached_numlightentities;
3889         numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3890         numshadowentities = rtlight->cached_numshadowentities;
3891         numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3892         numsurfaces = rtlight->cached_numsurfaces;
3893         lightentities = rtlight->cached_lightentities;
3894         lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3895         shadowentities = rtlight->cached_shadowentities;
3896         shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3897         shadowtrispvs = rtlight->cached_shadowtrispvs;
3898         lighttrispvs = rtlight->cached_lighttrispvs;
3899         surfacelist = rtlight->cached_surfacelist;
3900         castshadows = rtlight->castshadows;
3901
3902         // make this the active rtlight for rendering purposes
3903         R_Shadow_RenderMode_ActiveLight(rtlight);
3904
3905         if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3906         {
3907                 // optionally draw the illuminated areas
3908                 // for performance analysis by level designers
3909                 R_Shadow_RenderMode_VisibleLighting(false);
3910                 if (numsurfaces)
3911                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3912                 for (i = 0;i < numlightentities;i++)
3913                         R_Shadow_DrawEntityLight(lightentities[i]);
3914                 for (i = 0;i < numlightentities_noselfshadow;i++)
3915                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3916         }
3917
3918         if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3919         {
3920                 float borderbias;
3921                 int size;
3922                 float shadowmapoffsetnoselfshadow = 0;
3923                 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3924                 Matrix4x4_Abs(&radiustolight);
3925
3926                 size = rtlight->shadowmapatlassidesize;
3927                 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3928
3929                 //Con_Printf("distance %f lodlinear %i size %i\n", distance, lodlinear, size);
3930
3931                 if (rtlight->cached_numshadowentities_noselfshadow)
3932                         shadowmapoffsetnoselfshadow = rtlight->shadowmapatlassidesize * 2;
3933
3934                 // render lighting using the depth texture as shadowmap
3935                 // draw lighting in the unmasked areas
3936                 if (numsurfaces + numlightentities)
3937                 {
3938                         R_Shadow_RenderMode_Lighting(false, true, false);
3939                         // draw lighting in the unmasked areas
3940                         if (numsurfaces)
3941                                 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3942                         for (i = 0; i < numlightentities; i++)
3943                                 R_Shadow_DrawEntityLight(lightentities[i]);
3944                 }
3945                 // offset to the noselfshadow part of the atlas and draw those too
3946                 if (numlightentities_noselfshadow)
3947                 {
3948                         R_Shadow_RenderMode_Lighting(false, true, true);
3949                         for (i = 0; i < numlightentities_noselfshadow; i++)
3950                                 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3951                 }
3952
3953                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3954                 if (r_shadow_usingdeferredprepass)
3955                         R_Shadow_RenderMode_DrawDeferredLight(true);
3956         }
3957         else
3958         {
3959                 // draw lighting in the unmasked areas
3960                 R_Shadow_RenderMode_Lighting(false, false, false);
3961                 if (numsurfaces)
3962                         R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3963                 for (i = 0;i < numlightentities;i++)
3964                         R_Shadow_DrawEntityLight(lightentities[i]);
3965                 for (i = 0;i < numlightentities_noselfshadow;i++)
3966                         R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3967
3968                 // rasterize the box when rendering deferred lighting - the regular surface lighting only applies to transparent surfaces
3969                 if (r_shadow_usingdeferredprepass)
3970                         R_Shadow_RenderMode_DrawDeferredLight(false);
3971         }
3972 }
3973
3974 static void R_Shadow_FreeDeferred(void)
3975 {
3976         R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3977         r_shadow_prepassgeometryfbo = 0;
3978
3979         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3980         r_shadow_prepasslightingdiffusespecularfbo = 0;
3981
3982         R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
3983         r_shadow_prepasslightingdiffusefbo = 0;
3984
3985         if (r_shadow_prepassgeometrydepthbuffer)
3986                 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
3987         r_shadow_prepassgeometrydepthbuffer = NULL;
3988
3989         if (r_shadow_prepassgeometrynormalmaptexture)
3990                 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3991         r_shadow_prepassgeometrynormalmaptexture = NULL;
3992
3993         if (r_shadow_prepasslightingdiffusetexture)
3994                 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3995         r_shadow_prepasslightingdiffusetexture = NULL;
3996
3997         if (r_shadow_prepasslightingspeculartexture)
3998                 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3999         r_shadow_prepasslightingspeculartexture = NULL;
4000 }
4001
4002 void R_Shadow_DrawPrepass(void)
4003 {
4004         int i;
4005         int lnum;
4006         entity_render_t *ent;
4007         float clearcolor[4];
4008
4009         R_Mesh_ResetTextureState();
4010         GL_DepthMask(true);
4011         GL_ColorMask(1,1,1,1);
4012         GL_BlendFunc(GL_ONE, GL_ZERO);
4013         GL_Color(1,1,1,1);
4014         GL_DepthTest(true);
4015         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4016         Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4017         GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4018         if (r_timereport_active)
4019                 R_TimeReport("prepasscleargeom");
4020
4021         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4022                 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4023         if (r_timereport_active)
4024                 R_TimeReport("prepassworld");
4025
4026         for (i = 0;i < r_refdef.scene.numentities;i++)
4027         {
4028                 if (!r_refdef.viewcache.entityvisible[i])
4029                         continue;
4030                 ent = r_refdef.scene.entities[i];
4031                 if (ent->model && ent->model->DrawPrepass != NULL)
4032                         ent->model->DrawPrepass(ent);
4033         }
4034
4035         if (r_timereport_active)
4036                 R_TimeReport("prepassmodels");
4037
4038         GL_DepthMask(false);
4039         GL_ColorMask(1,1,1,1);
4040         GL_Color(1,1,1,1);
4041         GL_DepthTest(true);
4042         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4043         Vector4Set(clearcolor, 0, 0, 0, 0);
4044         GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4045         if (r_timereport_active)
4046                 R_TimeReport("prepassclearlit");
4047
4048         R_Shadow_RenderMode_Begin();
4049
4050         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4051                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4052
4053         R_Shadow_RenderMode_End();
4054
4055         if (r_timereport_active)
4056                 R_TimeReport("prepasslights");
4057 }
4058
4059 #define MAX_SCENELIGHTS 65536
4060 qboolean R_Shadow_PrepareLights_AddSceneLight(rtlight_t *rtlight)
4061 {
4062         if (r_shadow_scenemaxlights <= r_shadow_scenenumlights)
4063         {
4064                 if (r_shadow_scenenumlights >= MAX_SCENELIGHTS)
4065                         return false;
4066                 r_shadow_scenemaxlights *= 2;
4067                 r_shadow_scenemaxlights = bound(1024, r_shadow_scenemaxlights, MAX_SCENELIGHTS);
4068                 r_shadow_scenelightlist = (rtlight_t **)Mem_Realloc(r_main_mempool, r_shadow_scenelightlist, r_shadow_scenemaxlights * sizeof(rtlight_t *));
4069         }
4070         r_shadow_scenelightlist[r_shadow_scenenumlights++] = rtlight;
4071         return true;
4072 }
4073
4074 void R_Shadow_DrawLightSprites(void);
4075 void R_Shadow_PrepareLights(void)
4076 {
4077         int flag;
4078         int lnum;
4079         size_t lightindex;
4080         dlight_t *light;
4081         size_t range;
4082         float f;
4083
4084         int shadowmapborder = bound(1, r_shadow_shadowmapping_bordersize.integer, 16);
4085         int shadowmaptexturesize = bound(256, r_shadow_shadowmapping_texturesize.integer, (int)vid.maxtexturesize_2d);
4086         int shadowmapmaxsize = bound(shadowmapborder+2, r_shadow_shadowmapping_maxsize.integer, shadowmaptexturesize / 8);
4087
4088         if (r_shadow_shadowmaptexturesize != shadowmaptexturesize ||
4089                 !(r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4090                 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL32) ||
4091                 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4092                 r_shadow_shadowmapshadowsampler != r_shadow_shadowmapping_useshadowsampler.integer ||
4093                 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4094                 r_shadow_shadowmapborder != shadowmapborder ||
4095                 r_shadow_shadowmapmaxsize != shadowmapmaxsize ||
4096                 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4097                 R_Shadow_FreeShadowMaps();
4098
4099         r_shadow_usingshadowmaportho = false;
4100
4101         switch (vid.renderpath)
4102         {
4103         case RENDERPATH_GL32:
4104 #ifndef USE_GLES2
4105                 if (!r_shadow_deferred.integer || vid.maxdrawbuffers < 2)
4106                 {
4107                         r_shadow_usingdeferredprepass = false;
4108                         if (r_shadow_prepass_width)
4109                                 R_Shadow_FreeDeferred();
4110                         r_shadow_prepass_width = r_shadow_prepass_height = 0;
4111                         break;
4112                 }
4113
4114                 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4115                 {
4116                         R_Shadow_FreeDeferred();
4117
4118                         r_shadow_usingdeferredprepass = true;
4119                         r_shadow_prepass_width = vid.width;
4120                         r_shadow_prepass_height = vid.height;
4121                         r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4122                         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);
4123                         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);
4124                         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);
4125
4126                         // set up the geometry pass fbo (depth + normalmap)
4127                         r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4128                         R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4129                         // render depth into a renderbuffer and other important properties into the normalmap texture
4130
4131                         // set up the lighting pass fbo (diffuse + specular)
4132                         r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4133                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4134                         // render diffuse into one texture and specular into another,
4135                         // with depth and normalmap bound as textures,
4136                         // with depth bound as attachment as well
4137
4138                         // set up the lighting pass fbo (diffuse)
4139                         r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4140                         R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4141                         // render diffuse into one texture,
4142                         // with depth and normalmap bound as textures,
4143                         // with depth bound as attachment as well
4144                 }
4145 #endif
4146                 break;
4147         case RENDERPATH_GLES2:
4148                 r_shadow_usingdeferredprepass = false;
4149                 break;
4150         }
4151
4152         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);
4153
4154         r_shadow_scenenumlights = 0;
4155         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4156         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4157         for (lightindex = 0; lightindex < range; lightindex++)
4158         {
4159                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4160                 if (light && (light->flags & flag))
4161                 {
4162                         R_Shadow_PrepareLight(&light->rtlight);
4163                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4164                 }
4165         }
4166         if (r_refdef.scene.rtdlight)
4167         {
4168                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4169                 {
4170                         R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4171                         R_Shadow_PrepareLights_AddSceneLight(r_refdef.scene.lights[lnum]);
4172                 }
4173         }
4174         else if (gl_flashblend.integer)
4175         {
4176                 for (lnum = 0; lnum < r_refdef.scene.numlights; lnum++)
4177                 {
4178                         rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4179                         f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4180                         VectorScale(rtlight->color, f, rtlight->currentcolor);
4181                 }
4182         }
4183
4184         // when debugging a single light, we still want to run the prepare, so we only replace the light list afterward...
4185         if (r_shadow_debuglight.integer >= 0)
4186         {
4187                 r_shadow_scenenumlights = 0;
4188                 lightindex = r_shadow_debuglight.integer;
4189                 light = (dlight_t *)Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4190                 if (light)
4191                 {
4192                         R_Shadow_PrepareLight(&light->rtlight);
4193                         R_Shadow_PrepareLights_AddSceneLight(&light->rtlight);
4194                 }
4195         }
4196
4197         // if we're doing shadowmaps we need to prepare the atlas layout now
4198         if (R_Shadow_ShadowMappingEnabled())
4199         {
4200                 int lod;
4201
4202                 // allocate shadowmaps in the atlas now
4203                 // 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...
4204                 for (lod = 0; lod < 16; lod++)
4205                 {
4206                         int packing_success = 0;
4207                         int packing_failure = 0;
4208                         Mod_AllocLightmap_Reset(&r_shadow_shadowmapatlas_state);
4209                         // we actually have to reserve space for the R_DrawModelShadowMaps if that feature is active, it uses 0,0 so this is easy.
4210                         if (r_shadow_shadowmapatlas_modelshadows_size)
4211                                 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);
4212                         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4213                         {
4214                                 rtlight_t *rtlight = r_shadow_scenelightlist[lnum];
4215                                 int size = rtlight->shadowmapsidesize >> lod;
4216                                 int width, height;
4217                                 if (!rtlight->castshadows)
4218                                         continue;
4219                                 size = bound(r_shadow_shadowmapborder, size, r_shadow_shadowmaptexturesize);
4220                                 width = size * 2;
4221                                 height = size * 3;
4222                                 // when there are noselfshadow entities in the light bounds, we have to render two separate sets of shadowmaps :(
4223                                 if (rtlight->cached_numshadowentities_noselfshadow)
4224                                         width *= 2;
4225                                 if (Mod_AllocLightmap_Block(&r_shadow_shadowmapatlas_state, width, height, &rtlight->shadowmapatlasposition[0], &rtlight->shadowmapatlasposition[1]))
4226                                 {
4227                                         rtlight->shadowmapatlassidesize = size;
4228                                         packing_success++;
4229                                 }
4230                                 else
4231                                 {
4232                                         // note down that we failed to pack this one, it will have to disable shadows
4233                                         rtlight->shadowmapatlassidesize = 0;
4234                                         packing_failure++;
4235                                 }
4236                         }
4237                         // generally everything fits and we stop here on the first iteration
4238                         if (packing_failure == 0)
4239                                 break;
4240                 }
4241         }
4242
4243         if (r_editlights.integer)
4244                 R_Shadow_DrawLightSprites();
4245 }
4246
4247 void R_Shadow_DrawShadowMaps(void)
4248 {
4249         R_Shadow_RenderMode_Begin();
4250         R_Shadow_RenderMode_ActiveLight(NULL);
4251
4252         // now that we have a layout of shadowmaps in the atlas, we can render the shadowmaps
4253         R_Shadow_ClearShadowMapTexture();
4254
4255         // render model shadowmaps (r_shadows 2) if desired which will be sampled in the forward pass
4256         if (r_shadow_shadowmapatlas_modelshadows_size)
4257         {
4258                 R_Shadow_DrawModelShadowMaps();
4259                 // don't let sound skip if going slow
4260                 if (r_refdef.scene.extraupdate)
4261                         S_ExtraUpdate();
4262         }
4263
4264         if (R_Shadow_ShadowMappingEnabled())
4265         {
4266                 int lnum;
4267                 for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4268                         R_Shadow_DrawLightShadowMaps(r_shadow_scenelightlist[lnum]);
4269         }
4270
4271         R_Shadow_RenderMode_End();
4272 }
4273
4274 void R_Shadow_DrawLights(void)
4275 {
4276         int lnum;
4277
4278         R_Shadow_RenderMode_Begin();
4279
4280         for (lnum = 0; lnum < r_shadow_scenenumlights; lnum++)
4281                 R_Shadow_DrawLight(r_shadow_scenelightlist[lnum]);
4282
4283         R_Shadow_RenderMode_End();
4284 }
4285
4286 #define MAX_MODELSHADOWS 1024
4287 static int r_shadow_nummodelshadows;
4288 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4289
4290 void R_Shadow_PrepareModelShadows(void)
4291 {
4292         int i;
4293         float scale, size, radius, dot1, dot2;
4294         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4295         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4296         entity_render_t *ent;
4297
4298         r_shadow_nummodelshadows = 0;
4299         r_shadow_shadowmapatlas_modelshadows_size = 0;
4300
4301         if (!r_refdef.scene.numentities || r_refdef.scene.lightmapintensity <= 0.0f || r_shadows.integer <= 0)
4302                 return;
4303
4304         size = r_shadow_shadowmaptexturesize / 4;
4305         scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4306         radius = 0.5f * size / scale;
4307
4308         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4309         VectorCopy(prvmshadowdir, shadowdir);
4310         VectorNormalize(shadowdir);
4311         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4312         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4313         if (fabs(dot1) <= fabs(dot2))
4314                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4315         else
4316                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4317         VectorNormalize(shadowforward);
4318         CrossProduct(shadowdir, shadowforward, shadowright);
4319         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4320         VectorCopy(prvmshadowfocus, shadowfocus);
4321         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4322         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4323         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4324         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4325         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4326                 dot1 = 1;
4327         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4328
4329         shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4330         shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4331         shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4332         shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4333         shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4334         shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4335
4336         for (i = 0; i < r_refdef.scene.numentities; i++)
4337         {
4338                 ent = r_refdef.scene.entities[i];
4339                 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4340                         continue;
4341                 // cast shadows from anything of the map (submodels are optional)
4342                 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4343                 {
4344                         if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4345                                 break;
4346                         r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4347                         R_AnimCache_GetEntity(ent, false, false);
4348                 }
4349         }
4350
4351         if (r_shadow_nummodelshadows)
4352         {
4353                 r_shadow_shadowmapatlas_modelshadows_x = 0;
4354                 r_shadow_shadowmapatlas_modelshadows_y = 0;
4355                 r_shadow_shadowmapatlas_modelshadows_size = size;
4356         }
4357 }
4358
4359 static void R_Shadow_DrawModelShadowMaps(void)
4360 {
4361         int i;
4362         float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4363         entity_render_t *ent;
4364         vec3_t relativelightorigin;
4365         vec3_t relativelightdirection, relativeforward, relativeright;
4366         vec3_t relativeshadowmins, relativeshadowmaxs;
4367         vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4368         prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4369         float m[12];
4370         matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4371         r_viewport_t viewport;
4372
4373         size = r_shadow_shadowmapatlas_modelshadows_size;
4374         scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4375         radius = 0.5f / scale;
4376         nearclip = -r_shadows_throwdistance.value;
4377         farclip = r_shadows_throwdistance.value;
4378         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);
4379
4380         // set the parameters that will be used on the regular model renders using these shadows we're about to produce
4381         r_shadow_modelshadowmap_parameters[0] = size;
4382         r_shadow_modelshadowmap_parameters[1] = size;
4383         r_shadow_modelshadowmap_parameters[2] = 1.0;
4384         r_shadow_modelshadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4385         r_shadow_modelshadowmap_texturescale[0] = 1.0f / r_shadow_shadowmaptexturesize;
4386         r_shadow_modelshadowmap_texturescale[1] = 1.0f / r_shadow_shadowmaptexturesize;
4387         r_shadow_modelshadowmap_texturescale[2] = r_shadow_shadowmapatlas_modelshadows_x;
4388         r_shadow_modelshadowmap_texturescale[3] = r_shadow_shadowmapatlas_modelshadows_y;
4389         r_shadow_usingshadowmaportho = true;
4390
4391         Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4392         VectorCopy(prvmshadowdir, shadowdir);
4393         VectorNormalize(shadowdir);
4394         Math_atov(r_shadows_focus.string, prvmshadowfocus);
4395         VectorCopy(prvmshadowfocus, shadowfocus);
4396         VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4397         VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4398         VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4399         VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4400         dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4401         dot2 = DotProduct(r_refdef.view.up, shadowdir);
4402         if (fabs(dot1) <= fabs(dot2))
4403                 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4404         else
4405                 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4406         VectorNormalize(shadowforward);
4407         VectorM(scale, shadowforward, &m[0]);
4408         if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4409                 dot1 = 1;
4410         m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4411         CrossProduct(shadowdir, shadowforward, shadowright);
4412         VectorM(scale, shadowright, &m[4]);
4413         m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4414         VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4415         m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4416         Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4417         Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4418         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);
4419         R_SetViewport(&viewport);
4420
4421         VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4422
4423         // render into a slightly restricted region so that the borders of the
4424         // shadowmap area fade away, rather than streaking across everything
4425         // outside the usable area
4426         GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4427
4428         for (i = 0;i < r_shadow_nummodelshadows;i++)
4429         {
4430                 ent = r_shadow_modelshadows[i];
4431                 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4432                 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4433                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4434                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4435                 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4436                 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4437                 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4438                 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4439                 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4440                 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4441                 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4442                 RSurf_ActiveModelEntity(ent, false, false, false);
4443                 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4444                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
4445         }
4446
4447 #if 0
4448         if (r_test.integer)
4449         {
4450                 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4451                 CHECKGLERROR
4452                 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4453                 CHECKGLERROR
4454                 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4455                 Cvar_SetValueQuick(&r_test, 0);
4456                 Z_Free(rawpixels);
4457         }
4458 #endif
4459
4460         Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4461         Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4462         Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4463         Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4464         Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4465         Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4466 }
4467
4468 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4469 {
4470         float zdist;
4471         vec3_t centerorigin;
4472 #ifndef USE_GLES2
4473         float vertex3f[12];
4474 #endif
4475         // if it's too close, skip it
4476         if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4477                 return;
4478         zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4479         if (zdist < 32)
4480                 return;
4481         if (usequery && r_numqueries + 2 <= r_maxqueries)
4482         {
4483                 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4484                 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4485                 // 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
4486                 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4487
4488                 switch(vid.renderpath)
4489                 {
4490                 case RENDERPATH_GL32:
4491                 case RENDERPATH_GLES2:
4492 #ifndef USE_GLES2
4493                         CHECKGLERROR
4494                         // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4495                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_allpixels);
4496                         GL_DepthFunc(GL_ALWAYS);
4497                         R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4498                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4499                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4500                         qglEndQuery(GL_SAMPLES_PASSED);
4501                         GL_DepthFunc(GL_LEQUAL);
4502                         qglBeginQuery(GL_SAMPLES_PASSED, rtlight->corona_queryindex_visiblepixels);
4503                         R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4504                         R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
4505                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4506                         qglEndQuery(GL_SAMPLES_PASSED);
4507                         CHECKGLERROR
4508 #endif
4509                         break;
4510                 }
4511         }
4512         rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4513 }
4514
4515 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4516
4517 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4518 {
4519         vec3_t color;
4520         unsigned int occlude = 0;
4521
4522         // now we have to check the query result
4523         if (rtlight->corona_queryindex_visiblepixels)
4524         {
4525                 switch(vid.renderpath)
4526                 {
4527                 case RENDERPATH_GL32:
4528                 case RENDERPATH_GLES2:
4529 #ifndef USE_GLES2
4530                         // store the pixel counts into a uniform buffer for the shader to
4531                         // use - we'll never know the results on the cpu without
4532                         // synchronizing and we don't want that
4533 #define BUFFER_OFFSET(i)    ((GLint *)((unsigned char*)NULL + (i)))
4534                         if (!r_shadow_occlusion_buf) {
4535                                 qglGenBuffers(1, &r_shadow_occlusion_buf);
4536                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4537                                 qglBufferData(GL_QUERY_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
4538                         } else {
4539                                 qglBindBuffer(GL_QUERY_BUFFER, r_shadow_occlusion_buf);
4540                         }
4541                         qglGetQueryObjectiv(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT, BUFFER_OFFSET(0));
4542                         qglGetQueryObjectiv(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT, BUFFER_OFFSET(4));
4543                         qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
4544                         occlude = MATERIALFLAG_OCCLUDE;
4545                         cscale *= rtlight->corona_visibility;
4546                         CHECKGLERROR
4547                         break;
4548 #else
4549                         return;
4550 #endif
4551                 }
4552         }
4553         else
4554         {
4555                 if (CL_Cache_TraceLineSurfaces(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT).fraction < 1)
4556                         return;
4557         }
4558         VectorScale(rtlight->currentcolor, cscale, color);
4559         if (VectorLength(color) > (1.0f / 256.0f))
4560         {
4561                 float vertex3f[12];
4562                 qboolean negated = (color[0] + color[1] + color[2] < 0);
4563                 if(negated)
4564                 {
4565                         VectorNegate(color, color);
4566                         GL_BlendEquationSubtract(true);
4567                 }
4568                 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4569                 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);
4570                 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false, false);
4571                 if(negated)
4572                         GL_BlendEquationSubtract(false);
4573         }
4574 }
4575
4576 void R_Shadow_DrawCoronas(void)
4577 {
4578         int i, flag;
4579         qboolean usequery = false;
4580         size_t lightindex;
4581         dlight_t *light;
4582         rtlight_t *rtlight;
4583         size_t range;
4584         if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4585                 return;
4586         if (r_fb.water.renderingscene)
4587                 return;
4588         flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4589         R_EntityMatrix(&identitymatrix);
4590
4591         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4592
4593         // check occlusion of coronas, using occlusion queries or raytraces
4594         r_numqueries = 0;
4595         switch (vid.renderpath)
4596         {
4597         case RENDERPATH_GL32:
4598         case RENDERPATH_GLES2:
4599                 usequery = r_coronas_occlusionquery.integer;
4600 #ifndef USE_GLES2
4601                 if (usequery)
4602                 {
4603                         GL_ColorMask(0,0,0,0);
4604                         if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
4605                         if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4606                         {
4607                                 i = r_maxqueries;
4608                                 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
4609                                 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4610                                 CHECKGLERROR
4611                                 qglGenQueries(r_maxqueries - i, r_queries + i);
4612                                 CHECKGLERROR
4613                         }
4614                         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
4615                         GL_BlendFunc(GL_ONE, GL_ZERO);
4616                         GL_CullFace(GL_NONE);
4617                         GL_DepthMask(false);
4618                         GL_DepthRange(0, 1);
4619                         GL_PolygonOffset(0, 0);
4620                         GL_DepthTest(true);
4621                         R_Mesh_ResetTextureState();
4622                         R_SetupShader_Generic_NoTexture(false, false);
4623                 }
4624 #endif
4625                 break;
4626         }
4627         for (lightindex = 0;lightindex < range;lightindex++)
4628         {
4629                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4630                 if (!light)
4631                         continue;
4632                 rtlight = &light->rtlight;
4633                 rtlight->corona_visibility = 0;
4634                 rtlight->corona_queryindex_visiblepixels = 0;
4635                 rtlight->corona_queryindex_allpixels = 0;
4636                 if (!(rtlight->flags & flag))
4637                         continue;
4638                 if (rtlight->corona <= 0)
4639                         continue;
4640                 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4641                         continue;
4642                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4643         }
4644         for (i = 0;i < r_refdef.scene.numlights;i++)
4645         {
4646                 rtlight = r_refdef.scene.lights[i];
4647                 rtlight->corona_visibility = 0;
4648                 rtlight->corona_queryindex_visiblepixels = 0;
4649                 rtlight->corona_queryindex_allpixels = 0;
4650                 if (!(rtlight->flags & flag))
4651                         continue;
4652                 if (rtlight->corona <= 0)
4653                         continue;
4654                 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4655         }
4656         if (usequery)
4657                 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4658
4659         // now draw the coronas using the query data for intensity info
4660         for (lightindex = 0;lightindex < range;lightindex++)
4661         {
4662                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4663                 if (!light)
4664                         continue;
4665                 rtlight = &light->rtlight;
4666                 if (rtlight->corona_visibility <= 0)
4667                         continue;
4668                 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4669         }
4670         for (i = 0;i < r_refdef.scene.numlights;i++)
4671         {
4672                 rtlight = r_refdef.scene.lights[i];
4673                 if (rtlight->corona_visibility <= 0)
4674                         continue;
4675                 if (gl_flashblend.integer)
4676                         R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4677                 else
4678                         R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4679         }
4680 }
4681
4682
4683
4684 static dlight_t *R_Shadow_NewWorldLight(void)
4685 {
4686         return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4687 }
4688
4689 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)
4690 {
4691         matrix4x4_t matrix;
4692
4693         // 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
4694
4695         // validate parameters
4696         if (!cubemapname)
4697                 cubemapname = "";
4698
4699         // copy to light properties
4700         VectorCopy(origin, light->origin);
4701         light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4702         light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4703         light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4704         /*
4705         light->color[0] = max(color[0], 0);
4706         light->color[1] = max(color[1], 0);
4707         light->color[2] = max(color[2], 0);
4708         */
4709         light->color[0] = color[0];
4710         light->color[1] = color[1];
4711         light->color[2] = color[2];
4712         light->radius = max(radius, 0);
4713         light->style = style;
4714         light->shadow = shadowenable;
4715         light->corona = corona;
4716         strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4717         light->coronasizescale = coronasizescale;
4718         light->ambientscale = ambientscale;
4719         light->diffusescale = diffusescale;
4720         light->specularscale = specularscale;
4721         light->flags = flags;
4722
4723         // update renderable light data
4724         Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4725         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);
4726 }
4727
4728 static void R_Shadow_FreeWorldLight(dlight_t *light)
4729 {
4730         if (r_shadow_selectedlight == light)
4731                 r_shadow_selectedlight = NULL;
4732         R_RTLight_Uncompile(&light->rtlight);
4733         Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4734 }
4735
4736 void R_Shadow_ClearWorldLights(void)
4737 {
4738         size_t lightindex;
4739         dlight_t *light;
4740         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4741         for (lightindex = 0;lightindex < range;lightindex++)
4742         {
4743                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4744                 if (light)
4745                         R_Shadow_FreeWorldLight(light);
4746         }
4747         r_shadow_selectedlight = NULL;
4748 }
4749
4750 static void R_Shadow_SelectLight(dlight_t *light)
4751 {
4752         if (r_shadow_selectedlight)
4753                 r_shadow_selectedlight->selected = false;
4754         r_shadow_selectedlight = light;
4755         if (r_shadow_selectedlight)
4756                 r_shadow_selectedlight->selected = true;
4757 }
4758
4759 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4760 {
4761         // this is never batched (there can be only one)
4762         float vertex3f[12];
4763         R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4764         RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4765         R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4766 }
4767
4768 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4769 {
4770         float intensity;
4771         float s;
4772         vec3_t spritecolor;
4773         skinframe_t *skinframe;
4774         float vertex3f[12];
4775
4776         // this is never batched (due to the ent parameter changing every time)
4777         // so numsurfaces == 1 and surfacelist[0] == lightnumber
4778         const dlight_t *light = (dlight_t *)ent;
4779         s = EDLIGHTSPRSIZE;
4780
4781         R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4782
4783         intensity = 0.5f;
4784         VectorScale(light->color, intensity, spritecolor);
4785         if (VectorLength(spritecolor) < 0.1732f)
4786                 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4787         if (VectorLength(spritecolor) > 1.0f)
4788                 VectorNormalize(spritecolor);
4789
4790         // draw light sprite
4791         if (light->cubemapname[0] && !light->shadow)
4792                 skinframe = r_editlights_sprcubemapnoshadowlight;
4793         else if (light->cubemapname[0])
4794                 skinframe = r_editlights_sprcubemaplight;
4795         else if (!light->shadow)
4796                 skinframe = r_editlights_sprnoshadowlight;
4797         else
4798                 skinframe = r_editlights_sprlight;
4799
4800         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);
4801         R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4802
4803         // draw selection sprite if light is selected
4804         if (light->selected)
4805         {
4806                 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4807                 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false, false);
4808                 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4809         }
4810 }
4811
4812 void R_Shadow_DrawLightSprites(void)
4813 {
4814         size_t lightindex;
4815         dlight_t *light;
4816         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4817         for (lightindex = 0;lightindex < range;lightindex++)
4818         {
4819                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4820                 if (light)
4821                         R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4822         }
4823         if (!r_editlights_lockcursor)
4824                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4825 }
4826
4827 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4828 {
4829         unsigned int range;
4830         dlight_t *light;
4831         rtlight_t *rtlight;
4832         range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4833         if (lightindex >= range)
4834                 return -1;
4835         light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4836         if (!light)
4837                 return 0;
4838         rtlight = &light->rtlight;
4839         //if (!(rtlight->flags & flag))
4840         //      return 0;
4841         VectorCopy(rtlight->shadoworigin, origin);
4842         *radius = rtlight->radius;
4843         VectorCopy(rtlight->color, color);
4844         return 1;
4845 }
4846
4847 static void R_Shadow_SelectLightInView(void)
4848 {
4849         float bestrating, rating, temp[3];
4850         dlight_t *best;
4851         size_t lightindex;
4852         dlight_t *light;
4853         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4854         best = NULL;
4855         bestrating = 0;
4856
4857         if (r_editlights_lockcursor)
4858                 return;
4859         for (lightindex = 0;lightindex < range;lightindex++)
4860         {
4861                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4862                 if (!light)
4863                         continue;
4864                 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4865                 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4866                 if (rating >= 0.95)
4867                 {
4868                         rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4869                         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)
4870                         {
4871                                 bestrating = rating;
4872                                 best = light;
4873                         }
4874                 }
4875         }
4876         R_Shadow_SelectLight(best);
4877 }
4878
4879 void R_Shadow_LoadWorldLights(void)
4880 {
4881         int n, a, style, shadow, flags;
4882         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4883         float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4884         if (cl.worldmodel == NULL)
4885         {
4886                 Con_Print("No map loaded.\n");
4887                 return;
4888         }
4889         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4890         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4891         if (lightsstring)
4892         {
4893                 s = lightsstring;
4894                 n = 0;
4895                 while (*s)
4896                 {
4897                         /*
4898                         t = s;
4899                         shadow = true;
4900                         for (;COM_Parse(t, true) && strcmp(
4901                         if (COM_Parse(t, true))
4902                         {
4903                                 if (com_token[0] == '!')
4904                                 {
4905                                         shadow = false;
4906                                         origin[0] = atof(com_token+1);
4907                                 }
4908                                 else
4909                                         origin[0] = atof(com_token);
4910                                 if (Com_Parse(t
4911                         }
4912                         */
4913                         t = s;
4914                         while (*s && *s != '\n' && *s != '\r')
4915                                 s++;
4916                         if (!*s)
4917                                 break;
4918                         tempchar = *s;
4919                         shadow = true;
4920                         // check for modifier flags
4921                         if (*t == '!')
4922                         {
4923                                 shadow = false;
4924                                 t++;
4925                         }
4926                         *s = 0;
4927 #if _MSC_VER >= 1400
4928 #define sscanf sscanf_s
4929 #endif
4930                         cubemapname[sizeof(cubemapname)-1] = 0;
4931 #if MAX_QPATH != 128
4932 #error update this code if MAX_QPATH changes
4933 #endif
4934                         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
4935 #if _MSC_VER >= 1400
4936 , (unsigned int)sizeof(cubemapname)
4937 #endif
4938 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4939                         *s = tempchar;
4940                         if (a < 18)
4941                                 flags = LIGHTFLAG_REALTIMEMODE;
4942                         if (a < 17)
4943                                 specularscale = 1;
4944                         if (a < 16)
4945                                 diffusescale = 1;
4946                         if (a < 15)
4947                                 ambientscale = 0;
4948                         if (a < 14)
4949                                 coronasizescale = 0.25f;
4950                         if (a < 13)
4951                                 VectorClear(angles);
4952                         if (a < 10)
4953                                 corona = 0;
4954                         if (a < 9 || !strcmp(cubemapname, "\"\""))
4955                                 cubemapname[0] = 0;
4956                         // remove quotes on cubemapname
4957                         if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4958                         {
4959                                 size_t namelen;
4960                                 namelen = strlen(cubemapname) - 2;
4961                                 memmove(cubemapname, cubemapname + 1, namelen);
4962                                 cubemapname[namelen] = '\0';
4963                         }
4964                         if (a < 8)
4965                         {
4966                                 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);
4967                                 break;
4968                         }
4969                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4970                         if (*s == '\r')
4971                                 s++;
4972                         if (*s == '\n')
4973                                 s++;
4974                         n++;
4975                 }
4976                 if (*s)
4977                         Con_Printf("invalid rtlights file \"%s\"\n", name);
4978                 Mem_Free(lightsstring);
4979         }
4980 }
4981
4982 void R_Shadow_SaveWorldLights(void)
4983 {
4984         size_t lightindex;
4985         dlight_t *light;
4986         size_t bufchars, bufmaxchars;
4987         char *buf, *oldbuf;
4988         char name[MAX_QPATH];
4989         char line[MAX_INPUTLINE];
4990         size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4991         // I hate lines which are 3 times my screen size :( --blub
4992         if (!range)
4993                 return;
4994         if (cl.worldmodel == NULL)
4995         {
4996                 Con_Print("No map loaded.\n");
4997                 return;
4998         }
4999         dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5000         bufchars = bufmaxchars = 0;
5001         buf = NULL;
5002         for (lightindex = 0;lightindex < range;lightindex++)
5003         {
5004                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5005                 if (!light)
5006                         continue;
5007                 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5008                         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);
5009                 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5010                         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]);
5011                 else
5012                         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);
5013                 if (bufchars + strlen(line) > bufmaxchars)
5014                 {
5015                         bufmaxchars = bufchars + strlen(line) + 2048;
5016                         oldbuf = buf;
5017                         buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5018                         if (oldbuf)
5019                         {
5020                                 if (bufchars)
5021                                         memcpy(buf, oldbuf, bufchars);
5022                                 Mem_Free(oldbuf);
5023                         }
5024                 }
5025                 if (strlen(line))
5026                 {
5027                         memcpy(buf + bufchars, line, strlen(line));
5028                         bufchars += strlen(line);
5029                 }
5030         }
5031         if (bufchars)
5032                 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5033         if (buf)
5034                 Mem_Free(buf);
5035 }
5036
5037 void R_Shadow_LoadLightsFile(void)
5038 {
5039         int n, a, style;
5040         char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5041         float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5042         if (cl.worldmodel == NULL)
5043         {
5044                 Con_Print("No map loaded.\n");
5045                 return;
5046         }
5047         dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5048         lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5049         if (lightsstring)
5050         {
5051                 s = lightsstring;
5052                 n = 0;
5053                 while (*s)
5054                 {
5055                         t = s;
5056                         while (*s && *s != '\n' && *s != '\r')
5057                                 s++;
5058                         if (!*s)
5059                                 break;
5060                         tempchar = *s;
5061                         *s = 0;
5062                         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);
5063                         *s = tempchar;
5064                         if (a < 14)
5065                         {
5066                                 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);
5067                                 break;
5068                         }
5069                         radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5070                         radius = bound(15, radius, 4096);
5071                         VectorScale(color, (2.0f / (8388608.0f)), color);
5072                         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5073                         if (*s == '\r')
5074                                 s++;
5075                         if (*s == '\n')
5076                                 s++;
5077                         n++;
5078                 }
5079                 if (*s)
5080                         Con_Printf("invalid lights file \"%s\"\n", name);
5081                 Mem_Free(lightsstring);
5082         }
5083 }
5084
5085 // tyrlite/hmap2 light types in the delay field
5086 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5087
5088 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5089 {
5090         int entnum;
5091         int style;
5092         int islight;
5093         int skin;
5094         int pflags;
5095         //int effects;
5096         int type;
5097         int n;
5098         char *entfiledata;
5099         const char *data;
5100         float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5101         char key[256], value[MAX_INPUTLINE];
5102         char vabuf[1024];
5103
5104         if (cl.worldmodel == NULL)
5105         {
5106                 Con_Print("No map loaded.\n");
5107                 return;
5108         }
5109         // try to load a .ent file first
5110         dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5111         data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5112         // and if that is not found, fall back to the bsp file entity string
5113         if (!data)
5114                 data = cl.worldmodel->brush.entities;
5115         if (!data)
5116                 return;
5117         for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5118         {
5119                 type = LIGHTTYPE_MINUSX;
5120                 origin[0] = origin[1] = origin[2] = 0;
5121                 originhack[0] = originhack[1] = originhack[2] = 0;
5122                 angles[0] = angles[1] = angles[2] = 0;
5123                 color[0] = color[1] = color[2] = 1;
5124                 light[0] = light[1] = light[2] = 1;light[3] = 300;
5125                 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5126                 fadescale = 1;
5127                 lightscale = 1;
5128                 style = 0;
5129                 skin = 0;
5130                 pflags = 0;
5131                 //effects = 0;
5132                 islight = false;
5133                 while (1)
5134                 {
5135                         if (!COM_ParseToken_Simple(&data, false, false, true))
5136                                 break; // error
5137                         if (com_token[0] == '}')
5138                                 break; // end of entity
5139                         if (com_token[0] == '_')
5140                                 strlcpy(key, com_token + 1, sizeof(key));
5141                         else
5142                                 strlcpy(key, com_token, sizeof(key));
5143                         while (key[strlen(key)-1] == ' ') // remove trailing spaces
5144                                 key[strlen(key)-1] = 0;
5145                         if (!COM_ParseToken_Simple(&data, false, false, true))
5146                                 break; // error
5147                         strlcpy(value, com_token, sizeof(value));
5148
5149                         // now that we have the key pair worked out...
5150                         if (!strcmp("light", key))
5151                         {
5152                                 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5153                                 if (n == 1)
5154                                 {
5155                                         // quake
5156                                         light[0] = vec[0] * (1.0f / 256.0f);
5157                                         light[1] = vec[0] * (1.0f / 256.0f);
5158                                         light[2] = vec[0] * (1.0f / 256.0f);
5159                                         light[3] = vec[0];
5160                                 }
5161                                 else if (n == 4)
5162                                 {
5163                                         // halflife
5164                                         light[0] = vec[0] * (1.0f / 255.0f);
5165                                         light[1] = vec[1] * (1.0f / 255.0f);
5166                                         light[2] = vec[2] * (1.0f / 255.0f);
5167                                         light[3] = vec[3];
5168                                 }
5169                         }
5170                         else if (!strcmp("delay", key))
5171                                 type = atoi(value);
5172                         else if (!strcmp("origin", key))
5173                                 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5174                         else if (!strcmp("angle", key))
5175                                 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5176                         else if (!strcmp("angles", key))
5177                                 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5178                         else if (!strcmp("color", key))
5179                                 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5180                         else if (!strcmp("wait", key))
5181                                 fadescale = atof(value);
5182                         else if (!strcmp("classname", key))
5183                         {
5184                                 if (!strncmp(value, "light", 5))
5185                                 {
5186                                         islight = true;
5187                                         if (!strcmp(value, "light_fluoro"))
5188                                         {
5189                                                 originhack[0] = 0;
5190                                                 originhack[1] = 0;
5191                                                 originhack[2] = 0;
5192                                                 overridecolor[0] = 1;
5193                                                 overridecolor[1] = 1;
5194                                                 overridecolor[2] = 1;
5195                                         }
5196                                         if (!strcmp(value, "light_fluorospark"))
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_globe"))
5206                                         {
5207                                                 originhack[0] = 0;
5208                                                 originhack[1] = 0;
5209                                                 originhack[2] = 0;
5210                                                 overridecolor[0] = 1;
5211                                                 overridecolor[1] = 0.8;
5212                                                 overridecolor[2] = 0.4;
5213                                         }
5214                                         if (!strcmp(value, "light_flame_large_yellow"))
5215                                         {
5216                                                 originhack[0] = 0;
5217                                                 originhack[1] = 0;
5218                                                 originhack[2] = 0;
5219                                                 overridecolor[0] = 1;
5220                                                 overridecolor[1] = 0.5;
5221                                                 overridecolor[2] = 0.1;
5222                                         }
5223                                         if (!strcmp(value, "light_flame_small_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_torch_small_white"))
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_walltorch"))
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                                 }
5251                         }
5252                         else if (!strcmp("style", key))
5253                                 style = atoi(value);
5254                         else if (!strcmp("skin", key))
5255                                 skin = (int)atof(value);
5256                         else if (!strcmp("pflags", key))
5257                                 pflags = (int)atof(value);
5258                         //else if (!strcmp("effects", key))
5259                         //      effects = (int)atof(value);
5260                         else if (cl.worldmodel->type == mod_brushq3)
5261                         {
5262                                 if (!strcmp("scale", key))
5263                                         lightscale = atof(value);
5264                                 if (!strcmp("fade", key))
5265                                         fadescale = atof(value);
5266                         }
5267                 }
5268                 if (!islight)
5269                         continue;
5270                 if (lightscale <= 0)
5271                         lightscale = 1;
5272                 if (fadescale <= 0)
5273                         fadescale = 1;
5274                 if (color[0] == color[1] && color[0] == color[2])
5275                 {
5276                         color[0] *= overridecolor[0];
5277                         color[1] *= overridecolor[1];
5278                         color[2] *= overridecolor[2];
5279                 }
5280                 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5281                 color[0] = color[0] * light[0];
5282                 color[1] = color[1] * light[1];
5283                 color[2] = color[2] * light[2];
5284                 switch (type)
5285                 {
5286                 case LIGHTTYPE_MINUSX:
5287                         break;
5288                 case LIGHTTYPE_RECIPX:
5289                         radius *= 2;
5290                         VectorScale(color, (1.0f / 16.0f), color);
5291                         break;
5292                 case LIGHTTYPE_RECIPXX:
5293                         radius *= 2;
5294                         VectorScale(color, (1.0f / 16.0f), color);
5295                         break;
5296                 default:
5297                 case LIGHTTYPE_NONE:
5298                         break;
5299                 case LIGHTTYPE_SUN:
5300                         break;
5301                 case LIGHTTYPE_MINUSXX:
5302                         break;
5303                 }
5304                 VectorAdd(origin, originhack, origin);
5305                 if (radius >= 1)
5306                         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);
5307         }
5308         if (entfiledata)
5309                 Mem_Free(entfiledata);
5310 }
5311
5312
5313 static void R_Shadow_SetCursorLocationForView(void)
5314 {
5315         vec_t dist, push;
5316         vec3_t dest, endpos;
5317         trace_t trace;
5318         VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5319         trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT, collision_extendmovelength.value, true, false, NULL, false, true);
5320         if (trace.fraction < 1)
5321         {
5322                 dist = trace.fraction * r_editlights_cursordistance.value;
5323                 push = r_editlights_cursorpushback.value;
5324                 if (push > dist)
5325                         push = dist;
5326                 push = -push;
5327                 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5328                 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5329         }
5330         else
5331         {
5332                 VectorClear( endpos );
5333         }
5334         r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5335         r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5336         r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5337 }
5338
5339 void R_Shadow_UpdateWorldLightSelection(void)
5340 {
5341         if (r_editlights.integer)
5342         {
5343                 R_Shadow_SetCursorLocationForView();
5344                 R_Shadow_SelectLightInView();
5345         }
5346         else
5347                 R_Shadow_SelectLight(NULL);
5348 }
5349
5350 static void R_Shadow_EditLights_Clear_f(cmd_state_t *cmd)
5351 {
5352         R_Shadow_ClearWorldLights();
5353 }
5354
5355 void R_Shadow_EditLights_Reload_f(cmd_state_t *cmd)
5356 {
5357         if (!cl.worldmodel)
5358                 return;
5359         strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5360         R_Shadow_ClearWorldLights();
5361         if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
5362         {
5363                 R_Shadow_LoadWorldLights();
5364                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5365                         R_Shadow_LoadLightsFile();
5366         }
5367         if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
5368         {
5369                 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5370                         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5371         }
5372 }
5373
5374 static void R_Shadow_EditLights_Save_f(cmd_state_t *cmd)
5375 {
5376         if (!cl.worldmodel)
5377                 return;
5378         R_Shadow_SaveWorldLights();
5379 }
5380
5381 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(cmd_state_t *cmd)
5382 {
5383         R_Shadow_ClearWorldLights();
5384         R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5385 }
5386
5387 static void R_Shadow_EditLights_ImportLightsFile_f(cmd_state_t *cmd)
5388 {
5389         R_Shadow_ClearWorldLights();
5390         R_Shadow_LoadLightsFile();
5391 }
5392
5393 static void R_Shadow_EditLights_Spawn_f(cmd_state_t *cmd)
5394 {
5395         vec3_t color;
5396         if (!r_editlights.integer)
5397         {
5398                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5399                 return;
5400         }
5401         if (Cmd_Argc(cmd) != 1)
5402         {
5403                 Con_Print("r_editlights_spawn does not take parameters\n");
5404                 return;
5405         }
5406         color[0] = color[1] = color[2] = 1;
5407         R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5408 }
5409
5410 static void R_Shadow_EditLights_Edit_f(cmd_state_t *cmd)
5411 {
5412         vec3_t origin, angles, color;
5413         vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5414         int style, shadows, flags, normalmode, realtimemode;
5415         char cubemapname[MAX_INPUTLINE];
5416         if (!r_editlights.integer)
5417         {
5418                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5419                 return;
5420         }
5421         if (!r_shadow_selectedlight)
5422         {
5423                 Con_Print("No selected light.\n");
5424                 return;
5425         }
5426         VectorCopy(r_shadow_selectedlight->origin, origin);
5427         VectorCopy(r_shadow_selectedlight->angles, angles);
5428         VectorCopy(r_shadow_selectedlight->color, color);
5429         radius = r_shadow_selectedlight->radius;
5430         style = r_shadow_selectedlight->style;
5431         if (r_shadow_selectedlight->cubemapname)
5432                 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5433         else
5434                 cubemapname[0] = 0;
5435         shadows = r_shadow_selectedlight->shadow;
5436         corona = r_shadow_selectedlight->corona;
5437         coronasizescale = r_shadow_selectedlight->coronasizescale;
5438         ambientscale = r_shadow_selectedlight->ambientscale;
5439         diffusescale = r_shadow_selectedlight->diffusescale;
5440         specularscale = r_shadow_selectedlight->specularscale;
5441         flags = r_shadow_selectedlight->flags;
5442         normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5443         realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5444         if (!strcmp(Cmd_Argv(cmd, 1), "origin"))
5445         {
5446                 if (Cmd_Argc(cmd) != 5)
5447                 {
5448                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5449                         return;
5450                 }
5451                 origin[0] = atof(Cmd_Argv(cmd, 2));
5452                 origin[1] = atof(Cmd_Argv(cmd, 3));
5453                 origin[2] = atof(Cmd_Argv(cmd, 4));
5454         }
5455         else if (!strcmp(Cmd_Argv(cmd, 1), "originscale"))
5456         {
5457                 if (Cmd_Argc(cmd) != 5)
5458                 {
5459                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5460                         return;
5461                 }
5462                 origin[0] *= atof(Cmd_Argv(cmd, 2));
5463                 origin[1] *= atof(Cmd_Argv(cmd, 3));
5464                 origin[2] *= atof(Cmd_Argv(cmd, 4));
5465         }
5466         else if (!strcmp(Cmd_Argv(cmd, 1), "originx"))
5467         {
5468                 if (Cmd_Argc(cmd) != 3)
5469                 {
5470                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5471                         return;
5472                 }
5473                 origin[0] = atof(Cmd_Argv(cmd, 2));
5474         }
5475         else if (!strcmp(Cmd_Argv(cmd, 1), "originy"))
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[1] = atof(Cmd_Argv(cmd, 2));
5483         }
5484         else if (!strcmp(Cmd_Argv(cmd, 1), "originz"))
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[2] = atof(Cmd_Argv(cmd, 2));
5492         }
5493         else if (!strcmp(Cmd_Argv(cmd, 1), "move"))
5494         {
5495                 if (Cmd_Argc(cmd) != 5)
5496                 {
5497                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5498                         return;
5499                 }
5500                 origin[0] += atof(Cmd_Argv(cmd, 2));
5501                 origin[1] += atof(Cmd_Argv(cmd, 3));
5502                 origin[2] += atof(Cmd_Argv(cmd, 4));
5503         }
5504         else if (!strcmp(Cmd_Argv(cmd, 1), "movex"))
5505         {
5506                 if (Cmd_Argc(cmd) != 3)
5507                 {
5508                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5509                         return;
5510                 }
5511                 origin[0] += atof(Cmd_Argv(cmd, 2));
5512         }
5513         else if (!strcmp(Cmd_Argv(cmd, 1), "movey"))
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[1] += atof(Cmd_Argv(cmd, 2));
5521         }
5522         else if (!strcmp(Cmd_Argv(cmd, 1), "movez"))
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[2] += atof(Cmd_Argv(cmd, 2));
5530         }
5531         else if (!strcmp(Cmd_Argv(cmd, 1), "angles"))
5532         {
5533                 if (Cmd_Argc(cmd) != 5)
5534                 {
5535                         Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(cmd, 1));
5536                         return;
5537                 }
5538                 angles[0] = atof(Cmd_Argv(cmd, 2));
5539                 angles[1] = atof(Cmd_Argv(cmd, 3));
5540                 angles[2] = atof(Cmd_Argv(cmd, 4));
5541         }
5542         else if (!strcmp(Cmd_Argv(cmd, 1), "anglesx"))
5543         {
5544                 if (Cmd_Argc(cmd) != 3)
5545                 {
5546                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5547                         return;
5548                 }
5549                 angles[0] = atof(Cmd_Argv(cmd, 2));
5550         }
5551         else if (!strcmp(Cmd_Argv(cmd, 1), "anglesy"))
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[1] = atof(Cmd_Argv(cmd, 2));
5559         }
5560         else if (!strcmp(Cmd_Argv(cmd, 1), "anglesz"))
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[2] = atof(Cmd_Argv(cmd, 2));
5568         }
5569         else if (!strcmp(Cmd_Argv(cmd, 1), "color"))
5570         {
5571                 if (Cmd_Argc(cmd) != 5)
5572                 {
5573                         Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(cmd, 1));
5574                         return;
5575                 }
5576                 color[0] = atof(Cmd_Argv(cmd, 2));
5577                 color[1] = atof(Cmd_Argv(cmd, 3));
5578                 color[2] = atof(Cmd_Argv(cmd, 4));
5579         }
5580         else if (!strcmp(Cmd_Argv(cmd, 1), "radius"))
5581         {
5582                 if (Cmd_Argc(cmd) != 3)
5583                 {
5584                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5585                         return;
5586                 }
5587                 radius = atof(Cmd_Argv(cmd, 2));
5588         }
5589         else if (!strcmp(Cmd_Argv(cmd, 1), "colorscale"))
5590         {
5591                 if (Cmd_Argc(cmd) == 3)
5592                 {
5593                         double scale = atof(Cmd_Argv(cmd, 2));
5594                         color[0] *= scale;
5595                         color[1] *= scale;
5596                         color[2] *= scale;
5597                 }
5598                 else
5599                 {
5600                         if (Cmd_Argc(cmd) != 5)
5601                         {
5602                                 Con_Printf("usage: r_editlights_edit %s red green blue  (OR grey instead of red green blue)\n", Cmd_Argv(cmd, 1));
5603                                 return;
5604                         }
5605                         color[0] *= atof(Cmd_Argv(cmd, 2));
5606                         color[1] *= atof(Cmd_Argv(cmd, 3));
5607                         color[2] *= atof(Cmd_Argv(cmd, 4));
5608                 }
5609         }
5610         else if (!strcmp(Cmd_Argv(cmd, 1), "radiusscale") || !strcmp(Cmd_Argv(cmd, 1), "sizescale"))
5611         {
5612                 if (Cmd_Argc(cmd) != 3)
5613                 {
5614                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5615                         return;
5616                 }
5617                 radius *= atof(Cmd_Argv(cmd, 2));
5618         }
5619         else if (!strcmp(Cmd_Argv(cmd, 1), "style"))
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                 style = atoi(Cmd_Argv(cmd, 2));
5627         }
5628         else if (!strcmp(Cmd_Argv(cmd, 1), "cubemap"))
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                 if (Cmd_Argc(cmd) == 3)
5636                         strlcpy(cubemapname, Cmd_Argv(cmd, 2), sizeof(cubemapname));
5637                 else
5638                         cubemapname[0] = 0;
5639         }
5640         else if (!strcmp(Cmd_Argv(cmd, 1), "shadows"))
5641         {
5642                 if (Cmd_Argc(cmd) != 3)
5643                 {
5644                         Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(cmd, 1));
5645                         return;
5646                 }
5647                 shadows = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5648         }
5649         else if (!strcmp(Cmd_Argv(cmd, 1), "corona"))
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                 corona = atof(Cmd_Argv(cmd, 2));
5657         }
5658         else if (!strcmp(Cmd_Argv(cmd, 1), "coronasize"))
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                 coronasizescale = atof(Cmd_Argv(cmd, 2));
5666         }
5667         else if (!strcmp(Cmd_Argv(cmd, 1), "ambient"))
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                 ambientscale = atof(Cmd_Argv(cmd, 2));
5675         }
5676         else if (!strcmp(Cmd_Argv(cmd, 1), "diffuse"))
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                 diffusescale = atof(Cmd_Argv(cmd, 2));
5684         }
5685         else if (!strcmp(Cmd_Argv(cmd, 1), "specular"))
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                 specularscale = atof(Cmd_Argv(cmd, 2));
5693         }
5694         else if (!strcmp(Cmd_Argv(cmd, 1), "normalmode"))
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                 normalmode = Cmd_Argv(cmd, 2)[0] == 'y' || Cmd_Argv(cmd, 2)[0] == 'Y' || Cmd_Argv(cmd, 2)[0] == 't' || atoi(Cmd_Argv(cmd, 2));
5702         }
5703         else if (!strcmp(Cmd_Argv(cmd, 1), "realtimemode"))
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                 realtimemode = 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
5713         {
5714                 Con_Print("usage: r_editlights_edit [property] [value]\n");
5715                 Con_Print("Selected light's properties:\n");
5716                 Con_Printf("Origin       : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5717                 Con_Printf("Angles       : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5718                 Con_Printf("Color        : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5719                 Con_Printf("Radius       : %f\n", r_shadow_selectedlight->radius);
5720                 Con_Printf("Corona       : %f\n", r_shadow_selectedlight->corona);
5721                 Con_Printf("Style        : %i\n", r_shadow_selectedlight->style);
5722                 Con_Printf("Shadows      : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5723                 Con_Printf("Cubemap      : %s\n", r_shadow_selectedlight->cubemapname);
5724                 Con_Printf("CoronaSize   : %f\n", r_shadow_selectedlight->coronasizescale);
5725                 Con_Printf("Ambient      : %f\n", r_shadow_selectedlight->ambientscale);
5726                 Con_Printf("Diffuse      : %f\n", r_shadow_selectedlight->diffusescale);
5727                 Con_Printf("Specular     : %f\n", r_shadow_selectedlight->specularscale);
5728                 Con_Printf("NormalMode   : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5729                 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5730                 return;
5731         }
5732         flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5733         R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5734 }
5735
5736 static void R_Shadow_EditLights_EditAll_f(cmd_state_t *cmd)
5737 {
5738         size_t lightindex;
5739         dlight_t *light, *oldselected;
5740         size_t range;
5741
5742         if (!r_editlights.integer)
5743         {
5744                 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5745                 return;
5746         }
5747
5748         oldselected = r_shadow_selectedlight;
5749         // EditLights doesn't seem to have a "remove" command or something so:
5750         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5751         for (lightindex = 0;lightindex < range;lightindex++)
5752         {
5753                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5754                 if (!light)
5755                         continue;
5756                 R_Shadow_SelectLight(light);
5757                 R_Shadow_EditLights_Edit_f(&cmd_client);
5758         }
5759         // return to old selected (to not mess editing once selection is locked)
5760         R_Shadow_SelectLight(oldselected);
5761 }
5762
5763 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5764 {
5765         int lightnumber, lightcount;
5766         size_t lightindex, range;
5767         dlight_t *light;
5768         char temp[256];
5769         float x, y;
5770
5771         if (!r_editlights.integer)
5772                 return;
5773
5774         // update cvars so QC can query them
5775         if (r_shadow_selectedlight)
5776         {
5777                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5778                 Cvar_SetQuick(&r_editlights_current_origin, temp);
5779                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5780                 Cvar_SetQuick(&r_editlights_current_angles, temp);
5781                 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5782                 Cvar_SetQuick(&r_editlights_current_color, temp);
5783                 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
5784                 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
5785                 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
5786                 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
5787                 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
5788                 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
5789                 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
5790                 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
5791                 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
5792                 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
5793                 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
5794         }
5795
5796         // draw properties on screen
5797         if (!r_editlights_drawproperties.integer)
5798                 return;
5799         x = vid_conwidth.value - 320;
5800         y = 5;
5801         DrawQ_Pic(x-5, y-5, NULL, 250, 243, 0, 0, 0, 0.75, 0);
5802         lightnumber = -1;
5803         lightcount = 0;
5804         range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5805         for (lightindex = 0;lightindex < range;lightindex++)
5806         {
5807                 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5808                 if (!light)
5809                         continue;
5810                 if (light == r_shadow_selectedlight)
5811                         lightnumber = (int)lightindex;
5812                 lightcount++;
5813         }
5814         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;
5815         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;
5816         y += 8;
5817         if (r_shadow_selectedlight == NULL)
5818                 return;
5819         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;
5820         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;
5821         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;
5822         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;
5823         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;
5824         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;
5825         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;
5826         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;
5827         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;
5828         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;
5829         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;
5830         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;
5831         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;
5832         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;
5833         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;
5834         y += 8;
5835         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;
5836         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;
5837         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;
5838         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;
5839         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;
5840         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;
5841         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;
5842         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;
5843         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;
5844         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;
5845 }
5846
5847 static void R_Shadow_EditLights_ToggleShadow_f(cmd_state_t *cmd)
5848 {
5849         if (!r_editlights.integer)
5850         {
5851                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5852                 return;
5853         }
5854         if (!r_shadow_selectedlight)
5855         {
5856                 Con_Print("No selected light.\n");
5857                 return;
5858         }
5859         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);
5860 }
5861
5862 static void R_Shadow_EditLights_ToggleCorona_f(cmd_state_t *cmd)
5863 {
5864         if (!r_editlights.integer)
5865         {
5866                 Con_Print("Cannot spawn light when not in editing mode.  Set r_editlights to 1.\n");
5867                 return;
5868         }
5869         if (!r_shadow_selectedlight)
5870         {
5871                 Con_Print("No selected light.\n");
5872                 return;
5873         }
5874         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);
5875 }
5876
5877 static void R_Shadow_EditLights_Remove_f(cmd_state_t *cmd)
5878 {
5879         if (!r_editlights.integer)
5880         {
5881                 Con_Print("Cannot remove light when not in editing mode.  Set r_editlights to 1.\n");
5882                 return;
5883         }
5884         if (!r_shadow_selectedlight)
5885         {
5886                 Con_Print("No selected light.\n");
5887                 return;
5888         }
5889         R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5890         r_shadow_selectedlight = NULL;
5891 }
5892
5893 static void R_Shadow_EditLights_Help_f(cmd_state_t *cmd)
5894 {
5895         Con_Print(
5896 "Documentation on r_editlights system:\n"
5897 "Settings:\n"
5898 "r_editlights : enable/disable editing mode\n"
5899 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5900 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5901 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5902 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5903 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5904 "Commands:\n"
5905 "r_editlights_help : this help\n"
5906 "r_editlights_clear : remove all lights\n"
5907 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5908 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5909 "r_editlights_save : save to .rtlights file\n"
5910 "r_editlights_spawn : create a light with default settings\n"
5911 "r_editlights_edit command : edit selected light - more documentation below\n"
5912 "r_editlights_remove : remove selected light\n"
5913 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5914 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5915 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5916 "Edit commands:\n"
5917 "origin x y z : set light location\n"
5918 "originx x: set x component of light location\n"
5919 "originy y: set y component of light location\n"
5920 "originz z: set z component of light location\n"
5921 "move x y z : adjust light location\n"
5922 "movex x: adjust x component of light location\n"
5923 "movey y: adjust y component of light location\n"
5924 "movez z: adjust z component of light location\n"
5925 "angles x y z : set light angles\n"
5926 "anglesx x: set x component of light angles\n"
5927 "anglesy y: set y component of light angles\n"
5928 "anglesz z: set z component of light angles\n"
5929 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5930 "radius radius : set radius (size) of light\n"
5931 "colorscale grey : multiply color of light (1 does nothing)\n"
5932 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5933 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5934 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5935 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
5936 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5937 "cubemap basename : set filter cubemap of light\n"
5938 "shadows 1/0 : turn on/off shadows\n"
5939 "corona n : set corona intensity\n"
5940 "coronasize n : set corona size (0-1)\n"
5941 "ambient n : set ambient intensity (0-1)\n"
5942 "diffuse n : set diffuse intensity (0-1)\n"
5943 "specular n : set specular intensity (0-1)\n"
5944 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5945 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5946 "<nothing> : print light properties to console\n"
5947         );
5948 }
5949
5950 static void R_Shadow_EditLights_CopyInfo_f(cmd_state_t *cmd)
5951 {
5952         if (!r_editlights.integer)
5953         {
5954                 Con_Print("Cannot copy light info when not in editing mode.  Set r_editlights to 1.\n");
5955                 return;
5956         }
5957         if (!r_shadow_selectedlight)
5958         {
5959                 Con_Print("No selected light.\n");
5960                 return;
5961         }
5962         VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5963         VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5964         r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5965         r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5966         if (r_shadow_selectedlight->cubemapname)
5967                 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5968         else
5969                 r_shadow_bufferlight.cubemapname[0] = 0;
5970         r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5971         r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5972         r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5973         r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5974         r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5975         r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5976         r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5977 }
5978
5979 static void R_Shadow_EditLights_PasteInfo_f(cmd_state_t *cmd)
5980 {
5981         if (!r_editlights.integer)
5982         {
5983                 Con_Print("Cannot paste light info when not in editing mode.  Set r_editlights to 1.\n");
5984                 return;
5985         }
5986         if (!r_shadow_selectedlight)
5987         {
5988                 Con_Print("No selected light.\n");
5989                 return;
5990         }
5991         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);
5992 }
5993
5994 static void R_Shadow_EditLights_Lock_f(cmd_state_t *cmd)
5995 {
5996         if (!r_editlights.integer)
5997         {
5998                 Con_Print("Cannot lock on light when not in editing mode.  Set r_editlights to 1.\n");
5999                 return;
6000         }
6001         if (r_editlights_lockcursor)
6002         {
6003                 r_editlights_lockcursor = false;
6004                 return;
6005         }
6006         if (!r_shadow_selectedlight)
6007         {
6008                 Con_Print("No selected light to lock on.\n");
6009                 return;
6010         }
6011         r_editlights_lockcursor = true;
6012 }
6013
6014 static void R_Shadow_EditLights_Init(void)
6015 {
6016         Cvar_RegisterVariable(&r_editlights);
6017         Cvar_RegisterVariable(&r_editlights_cursordistance);
6018         Cvar_RegisterVariable(&r_editlights_cursorpushback);
6019         Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6020         Cvar_RegisterVariable(&r_editlights_cursorgrid);
6021         Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6022         Cvar_RegisterVariable(&r_editlights_drawproperties);
6023         Cvar_RegisterVariable(&r_editlights_current_origin);
6024         Cvar_RegisterVariable(&r_editlights_current_angles);
6025         Cvar_RegisterVariable(&r_editlights_current_color);
6026         Cvar_RegisterVariable(&r_editlights_current_radius);
6027         Cvar_RegisterVariable(&r_editlights_current_corona);
6028         Cvar_RegisterVariable(&r_editlights_current_coronasize);
6029         Cvar_RegisterVariable(&r_editlights_current_style);
6030         Cvar_RegisterVariable(&r_editlights_current_shadows);
6031         Cvar_RegisterVariable(&r_editlights_current_cubemap);
6032         Cvar_RegisterVariable(&r_editlights_current_ambient);
6033         Cvar_RegisterVariable(&r_editlights_current_diffuse);
6034         Cvar_RegisterVariable(&r_editlights_current_specular);
6035         Cvar_RegisterVariable(&r_editlights_current_normalmode);
6036         Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6037         Cmd_AddCommand(&cmd_client, "r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6038         Cmd_AddCommand(&cmd_client, "r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6039         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)");
6040         Cmd_AddCommand(&cmd_client, "r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6041         Cmd_AddCommand(&cmd_client, "r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6042         Cmd_AddCommand(&cmd_client, "r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6043         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)");
6044         Cmd_AddCommand(&cmd_client, "r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6045         Cmd_AddCommand(&cmd_client, "r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6046         Cmd_AddCommand(&cmd_client, "r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6047         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)");
6048         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)");
6049         Cmd_AddCommand(&cmd_client, "r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6050         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)");
6051         Cmd_AddCommand(&cmd_client, "r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6052 }
6053
6054
6055
6056 /*
6057 =============================================================================
6058
6059 LIGHT SAMPLING
6060
6061 =============================================================================
6062 */
6063
6064 void R_CompleteLightPoint(float *ambient, float *diffuse, float *lightdir, const vec3_t p, const int flags, float lightmapintensity, float ambientintensity)
6065 {
6066         int i, numlights, flag, q;
6067         rtlight_t *light;
6068         dlight_t *dlight;
6069         float relativepoint[3];
6070         float color[3];
6071         float dist;
6072         float dist2;
6073         float intensity;
6074         float sa[3], sx[3], sy[3], sz[3], sd[3];
6075         float lightradius2;
6076
6077         // use first order spherical harmonics to combine directional lights
6078         for (q = 0; q < 3; q++)
6079                 sa[q] = sx[q] = sy[q] = sz[q] = sd[q] = 0;
6080
6081         if (flags & LP_LIGHTMAP)
6082         {
6083                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6084                 {
6085                         float tempambient[3];
6086                         for (q = 0; q < 3; q++)
6087                                 tempambient[q] = color[q] = relativepoint[q] = 0;
6088                         r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6089                         // calculate a weighted average light direction as well
6090                         intensity = VectorLength(color);
6091                         for (q = 0; q < 3; q++)
6092                         {
6093                                 sa[q] += (0.5f * color[q] + tempambient[q]) * lightmapintensity;
6094                                 sx[q] += (relativepoint[0] * color[q]) * lightmapintensity;
6095                                 sy[q] += (relativepoint[1] * color[q]) * lightmapintensity;
6096                                 sz[q] += (relativepoint[2] * color[q]) * lightmapintensity;
6097                                 sd[q] += (intensity * relativepoint[q]) * lightmapintensity;
6098                         }
6099                 }
6100                 else
6101                 {
6102                         // unlit map - fullbright but scaled by lightmapintensity
6103                         for (q = 0; q < 3; q++)
6104                                 sa[q] += lightmapintensity;
6105                 }
6106         }
6107
6108         if (flags & LP_RTWORLD)
6109         {
6110                 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6111                 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6112                 for (i = 0; i < numlights; i++)
6113                 {
6114                         dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6115                         if (!dlight)
6116                                 continue;
6117                         light = &dlight->rtlight;
6118                         if (!(light->flags & flag))
6119                                 continue;
6120                         // sample
6121                         lightradius2 = light->radius * light->radius;
6122                         VectorSubtract(light->shadoworigin, p, relativepoint);
6123                         dist2 = VectorLength2(relativepoint);
6124                         if (dist2 >= lightradius2)
6125                                 continue;
6126                         dist = sqrt(dist2) / light->radius;
6127                         intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6128                         if (intensity <= 0.0f)
6129                                 continue;
6130                         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)
6131                                 continue;
6132                         for (q = 0; q < 3; q++)
6133                                 color[q] = light->currentcolor[q] * intensity;
6134                         intensity = VectorLength(color);
6135                         VectorNormalize(relativepoint);
6136                         for (q = 0; q < 3; q++)
6137                         {
6138                                 sa[q] += 0.5f * color[q];
6139                                 sx[q] += relativepoint[0] * color[q];
6140                                 sy[q] += relativepoint[1] * color[q];
6141                                 sz[q] += relativepoint[2] * color[q];
6142                                 sd[q] += intensity * relativepoint[q];
6143                         }
6144                 }
6145                 // FIXME: sample bouncegrid too!
6146         }
6147
6148         if (flags & LP_DYNLIGHT)
6149         {
6150                 // sample dlights
6151                 for (i = 0;i < r_refdef.scene.numlights;i++)
6152                 {
6153                         light = r_refdef.scene.lights[i];
6154                         // sample
6155                         lightradius2 = light->radius * light->radius;
6156                         VectorSubtract(light->shadoworigin, p, relativepoint);
6157                         dist2 = VectorLength2(relativepoint);
6158                         if (dist2 >= lightradius2)
6159                                 continue;
6160                         dist = sqrt(dist2) / light->radius;
6161                         intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6162                         if (intensity <= 0.0f)
6163                                 continue;
6164                         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)
6165                                 continue;
6166                         for (q = 0; q < 3; q++)
6167                                 color[q] = light->currentcolor[q] * intensity;
6168                         intensity = VectorLength(color);
6169                         VectorNormalize(relativepoint);
6170                         for (q = 0; q < 3; q++)
6171                         {
6172                                 sa[q] += 0.5f * color[q];
6173                                 sx[q] += relativepoint[0] * color[q];
6174                                 sy[q] += relativepoint[1] * color[q];
6175                                 sz[q] += relativepoint[2] * color[q];
6176                                 sd[q] += intensity * relativepoint[q];
6177                         }
6178                 }
6179         }
6180
6181         // calculate the weighted-average light direction (bentnormal)
6182         for (q = 0; q < 3; q++)
6183                 lightdir[q] = sd[q];
6184         VectorNormalize(lightdir);
6185         for (q = 0; q < 3; q++)
6186         {
6187                 // extract the diffuse color along the chosen direction and scale it
6188                 diffuse[q] = (lightdir[0] * sx[q] + lightdir[1] * sy[q] + lightdir[2] * sz[q]);
6189                 // subtract some of diffuse from ambient
6190                 ambient[q] = sa[q] + -0.333f * diffuse[q] + ambientintensity;
6191         }
6192 }