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