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