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