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