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