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