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