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