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