diff --git a/assets/voxygen/shaders/figure-frag.glsl b/assets/voxygen/shaders/figure-frag.glsl index fea577e89b..4384353e4a 100644 --- a/assets/voxygen/shaders/figure-frag.glsl +++ b/assets/voxygen/shaders/figure-frag.glsl @@ -92,9 +92,9 @@ void main() { // vec3 f_col = f_col_light.rgb; // float f_ao = f_col_light.a; - float f_ao, f_glow; + float f_ao, f_glow, f_ao_unused; uint material = 0xFFu; - vec3 f_col = greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_ao, f_glow, material); + vec3 f_col = greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_ao, f_glow, f_ao_unused, material); #ifdef EXPERIMENTAL_BAREMINIMUM tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_ao), 1); diff --git a/assets/voxygen/shaders/include/srgb.glsl b/assets/voxygen/shaders/include/srgb.glsl index d816a7f528..30631f830c 100644 --- a/assets/voxygen/shaders/include/srgb.glsl +++ b/assets/voxygen/shaders/include/srgb.glsl @@ -620,35 +620,36 @@ vec3 compute_attenuation_point(vec3 wpos, vec3 ray_dir, vec3 mu, float surface_a //} //#endif -vec3 greedy_extract_col_light_attr(texture2D t_col_light, sampler s_col_light, vec2 f_uv_pos, out float f_light, out float f_glow, out uint f_attr) { +vec3 greedy_extract_col_light_attr(texture2D t_col_light, sampler s_col_light, vec2 f_uv_pos, out float f_light, out float f_glow, out float f_ao, out uint f_attr) { uvec4 f_col_light = uvec4(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos), 0) * 255); vec3 f_col = vec3( float(((f_col_light.r & 0x7u) << 1u) | (f_col_light.b & 0xF0u)), - float(f_col_light.a), + float(f_col_light.a & 0xFE), float(((f_col_light.g & 0x7u) << 1u) | ((f_col_light.b & 0x0Fu) << 4u)) ) / 255.0; // TODO: Figure out how to use `texture` and modulation to avoid needing to do manual filtering - vec2 light_00 = vec2(uvec2(f_col_light.rg) >> 3u); - vec2 light_10 = vec2(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 0), 0).rg * 255.0) >> 3u); - vec2 light_01 = vec2(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(0, 1), 0).rg * 255.0) >> 3u); - vec2 light_11 = vec2(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 1), 0).rg * 255.0) >> 3u); - vec2 light_0 = mix(light_00, light_01, fract(f_uv_pos.y)); - vec2 light_1 = mix(light_10, light_11, fract(f_uv_pos.y)); - vec2 light = mix(light_0, light_1, fract(f_uv_pos.x)); + vec3 light_00 = vec3(uvec2(f_col_light.rg) >> 3u, f_col_light.a & 1u); + vec3 light_10 = vec3(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 0), 0).rg * 255.0) >> 3u, uint(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 0), 0).a * 255.0) & 1u); + vec3 light_01 = vec3(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(0, 1), 0).rg * 255.0) >> 3u, uint(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(0, 1), 0).a * 255.0) & 1u); + vec3 light_11 = vec3(uvec2(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 1), 0).rg * 255.0) >> 3u, uint(texelFetch(sampler2D(t_col_light, s_col_light), ivec2(f_uv_pos) + ivec2(1, 1), 0).a * 255.0) & 1u); + vec3 light_0 = mix(light_00, light_01, fract(f_uv_pos.y)); + vec3 light_1 = mix(light_10, light_11, fract(f_uv_pos.y)); + vec3 light = mix(light_0, light_1, fract(f_uv_pos.x)); // TODO: Use `texture` instead //vec2 light = texture(t_col_light, f_uv_pos).xy / 31; + f_ao = light.z; f_light = light.x / 31.0; f_glow = light.y / 31.0; f_attr = f_col_light.g >> 3u; return srgb_to_linear(f_col); } -vec3 greedy_extract_col_light_glow(texture2D t_col_light, sampler s_col_light, vec2 f_uv_pos, out float f_light, out float f_glow) { +vec3 greedy_extract_col_light_glow(texture2D t_col_light, sampler s_col_light, vec2 f_uv_pos, out float f_light, out float f_ao, out float f_glow) { uint f_attr; - return greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_light, f_glow, f_attr); + return greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_light, f_glow, f_ao, f_attr); } #endif diff --git a/assets/voxygen/shaders/sprite-frag.glsl b/assets/voxygen/shaders/sprite-frag.glsl index c712d6e496..e6df9501ce 100644 --- a/assets/voxygen/shaders/sprite-frag.glsl +++ b/assets/voxygen/shaders/sprite-frag.glsl @@ -40,8 +40,8 @@ layout(location = 0) out vec4 tgt_color; const float FADE_DIST = 32.0; void main() { - float f_ao, f_glow; - vec3 f_col = greedy_extract_col_light_glow(t_col_light, s_col_light, f_uv_pos, f_ao, f_glow); + float f_ao, f_glow, f_ao_unused; + vec3 f_col = greedy_extract_col_light_glow(t_col_light, s_col_light, f_uv_pos, f_ao, f_ao_unused, f_glow); #ifdef EXPERIMENTAL_BAREMINIMUM tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_ao), 1); diff --git a/assets/voxygen/shaders/terrain-frag.glsl b/assets/voxygen/shaders/terrain-frag.glsl index 44c29b56ca..668c06fea0 100644 --- a/assets/voxygen/shaders/terrain-frag.glsl +++ b/assets/voxygen/shaders/terrain-frag.glsl @@ -84,8 +84,8 @@ void main() { vec2 f_uv_pos = f_uv_pos + atlas_offs.xy; // vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize); // float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0; - float f_light, f_glow; - vec3 f_col = greedy_extract_col_light_glow(t_col_light, s_col_light, f_uv_pos, f_light, f_glow); + float f_light, f_glow, f_ao; + vec3 f_col = greedy_extract_col_light_glow(t_col_light, s_col_light, f_uv_pos, f_light, f_ao, f_glow); #ifdef EXPERIMENTAL_BAREMINIMUM tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_light), 1); @@ -391,6 +391,8 @@ void main() { max_light += lights_at(f_pos, f_norm, view_dir, mu, cam_attenuation, fluid_alt, k_a, k_d, k_s, alpha, f_norm, 1.0, emitted_light, reflected_light); + reflected_light *= 0.3 + f_ao * 0.7; + #ifndef EXPERIMENTAL_NOCAUSTICS #if (FLUID_MODE == FLUID_MODE_SHINY) if (faces_fluid) { diff --git a/voxygen/src/mesh/greedy.rs b/voxygen/src/mesh/greedy.rs index 8171859784..675611c0d0 100644 --- a/voxygen/src/mesh/greedy.rs +++ b/voxygen/src/mesh/greedy.rs @@ -9,7 +9,7 @@ type TodoRect = ( Vec3, ); -pub struct GreedyConfig { +pub struct GreedyConfig { pub data: D, /// The minimum position to mesh, in the coordinate system used /// for queries against the volume. @@ -31,6 +31,9 @@ pub struct GreedyConfig { /// the number of *horizontal* planes large enough to cover the whole /// chunk. pub greedy_size_cross: Vec3, + /// Given a position, return the AO information for the voxel at that + /// position (0.0 - 1.0). + pub get_ao: FA, /// Given a position, return the lighting information for the voxel at that /// position. pub get_light: FL, @@ -367,16 +370,17 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> { /// Returns an estimate of the bounds of the current meshed model. /// /// For more information on the config parameter, see [GreedyConfig]. - pub fn push( + pub fn push( &mut self, - config: GreedyConfig, + config: GreedyConfig, ) where + FA: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FL: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FG: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FO: for<'r> FnMut(&'r mut D, Vec3) -> bool + 'a, FS: for<'r> FnMut(&'r mut D, Vec3, Vec3, Vec2>) -> Option<(bool, M)>, FP: FnMut(Vec2, Vec2>, Vec3, Vec2>, Vec3, &M), - FT: for<'r> FnMut(&'r mut D, Vec3, u8, u8) -> [u8; 4] + 'a, + FT: for<'r> FnMut(&'r mut D, Vec3, u8, u8, bool) -> [u8; 4] + 'a, { span!(_guard, "push", "GreedyMesh::push"); let cont = greedy_mesh( @@ -401,7 +405,7 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> { span!(_guard, "finalize", "GreedyMesh::finalize"); let cur_size = self.col_lights_size; let col_lights = vec![ - TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254)); + TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254), true); cur_size.x as usize * cur_size.y as usize ]; let mut col_lights_info = (col_lights, cur_size); @@ -414,7 +418,9 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> { pub fn max_size(&self) -> Vec2 { self.max_size } } -fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FO, FS, FP, FT, Allocator: AtlasAllocator>( + + +fn greedy_mesh<'a, M: PartialEq, D: 'a, FA, FL, FG, FO, FS, FP, FT, Allocator: AtlasAllocator>( atlas: &mut Allocator, col_lights_size: &mut Vec2, max_size: Vec2, @@ -423,21 +429,23 @@ fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FO, FS, FP, FT, Allocator: Atlas draw_delta, greedy_size, greedy_size_cross, + get_ao, get_light, get_glow, get_opacity, mut should_draw, mut push_quad, make_face_texel, - }: GreedyConfig, + }: GreedyConfig, ) -> Box> where + FA: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FL: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FG: for<'r> FnMut(&'r mut D, Vec3) -> f32 + 'a, FO: for<'r> FnMut(&'r mut D, Vec3) -> bool + 'a, FS: for<'r> FnMut(&'r mut D, Vec3, Vec3, Vec2>) -> Option<(bool, M)>, FP: FnMut(Vec2, Vec2>, Vec3, Vec2>, Vec3, &M), - FT: for<'r> FnMut(&'r mut D, Vec3, u8, u8) -> [u8; 4] + 'a, + FT: for<'r> FnMut(&'r mut D, Vec3, u8, u8, bool) -> [u8; 4] + 'a, { span!(_guard, "greedy_mesh"); // TODO: Collect information to see if we can choose a good value here. @@ -573,6 +581,7 @@ where &mut data, todo_rects, draw_delta, + get_ao, get_light, get_glow, get_opacity, @@ -725,10 +734,11 @@ fn draw_col_lights( data: &mut D, todo_rects: Vec, draw_delta: Vec3, + mut get_ao: impl FnMut(&mut D, Vec3) -> f32, mut get_light: impl FnMut(&mut D, Vec3) -> f32, mut get_glow: impl FnMut(&mut D, Vec3) -> f32, mut get_opacity: impl FnMut(&mut D, Vec3) -> bool, - mut make_face_texel: impl FnMut(&mut D, Vec3, u8, u8) -> [u8; 4], + mut make_face_texel: impl FnMut(&mut D, Vec3, u8, u8, bool) -> [u8; 4], ) { todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| { // NOTE: Conversions are safe because width, height, and offset must be @@ -793,6 +803,15 @@ fn draw_col_lights( 0.0 } ) / 4.0; + let ao = (get_ao(data, light_pos) + + get_ao(data, light_pos - uv.x) + + get_ao(data, light_pos - uv.y) + + if direct_u_opacity || direct_v_opacity { + get_ao(data, light_pos - uv.x - uv.y) + } else { + 0.0 + }) + / 4.0; let glowiness = (get_glow(data, light_pos) + get_glow(data, light_pos - uv.x) + get_glow(data, light_pos - uv.y) @@ -804,7 +823,8 @@ fn draw_col_lights( / 4.0; let light = (darkness * 31.5) as u8; let glow = (glowiness * 31.5) as u8; - *col_light = make_face_texel(data, pos, light, glow); + let ao = ao > 0.7; + *col_light = make_face_texel(data, pos, light, glow, ao); }); }); }); diff --git a/voxygen/src/mesh/segment.rs b/voxygen/src/mesh/segment.rs index 068d38ad8f..22e892d3e3 100644 --- a/voxygen/src/mesh/segment.rs +++ b/voxygen/src/mesh/segment.rs @@ -78,6 +78,7 @@ where draw_delta, greedy_size, greedy_size_cross, + get_ao: |_: &mut V, _: Vec3| 1.0, get_light, get_glow, get_opacity, @@ -93,7 +94,7 @@ where |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), )); }, - make_face_texel: |vol: &mut V, pos, light, _| { + make_face_texel: |vol: &mut V, pos, light, _, _| { let cell = vol.get(pos).ok(); let (glowy, shiny) = cell .map(|c| (c.is_glowy(), c.is_shiny())) @@ -218,6 +219,7 @@ where draw_delta, greedy_size, greedy_size_cross, + get_ao: |_: &mut _, _: Vec3| 1.0, get_light, get_glow, get_opacity, @@ -233,8 +235,8 @@ where |atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta), )); }, - make_face_texel: move |flat: &mut _, pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(flat, pos)) + make_face_texel: move |flat: &mut _, pos, light, glow, ao| { + TerrainVertex::make_col_light(light, glow, get_color(flat, pos), ao) }, }); @@ -305,6 +307,7 @@ where draw_delta, greedy_size, greedy_size_cross, + get_ao: |_: &mut V, _: Vec3| 1.0, get_light, get_glow, get_opacity, @@ -320,8 +323,8 @@ where |atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm), )); }, - make_face_texel: move |vol: &mut V, pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(vol, pos)) + make_face_texel: move |vol: &mut V, pos, light, glow, ao| { + TerrainVertex::make_col_light(light, glow, get_color(vol, pos), ao) }, }); diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 71a47d4e60..70a8e29cea 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -375,6 +375,9 @@ pub fn generate_mesh<'a, V: RectRasterableVol + ReadVol + Debug + ' light(pos + range.min) } }; + let get_ao = |_: &mut (), pos: Vec3| { + if flat_get(pos).is_opaque() { 0.0 } else { 1.0 } + }; let get_glow = |_: &mut (), pos: Vec3| glow(pos + range.min); let get_color = |_: &mut (), pos: Vec3| flat_get(pos).get_color().unwrap_or_else(Rgb::zero); @@ -399,6 +402,7 @@ pub fn generate_mesh<'a, V: RectRasterableVol + ReadVol + Debug + ' draw_delta, greedy_size, greedy_size_cross, + get_ao, get_light, get_glow, get_opacity, @@ -427,8 +431,8 @@ pub fn generate_mesh<'a, V: RectRasterableVol + ReadVol + Debug + ' )); }, }, - make_face_texel: |data: &mut (), pos, light, glow| { - TerrainVertex::make_col_light(light, glow, get_color(data, pos)) + make_face_texel: |data: &mut (), pos, light, glow, ao| { + TerrainVertex::make_col_light(light, glow, get_color(data, pos), ao) }, }); diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index 920e1c8c8b..5284cb723e 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -67,6 +67,7 @@ impl Vertex { // 0 to 31 glow: u8, col: Rgb, + ao: bool, ) -> [u8; 4] { //[col.r, col.g, col.b, light] // It would be nice for this to be cleaner, but we want to squeeze 5 fields into @@ -92,7 +93,7 @@ impl Vertex { (light.min(31) << 3) | ((col.r >> 1) & 0b111), (glow.min(31) << 3) | ((col.b >> 1) & 0b111), (col.r & 0b11110000) | (col.b >> 4), - col.g, // Green is lucky, it remains unscathed + (col.g & 0xFE) | ao as u8, // Green is lucky, it remains unscathed ] } diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index 29ae3be672..3166dfd61a 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -12,7 +12,7 @@ use common::{ assets::{AssetExt, DotVoxAsset}, comp::{ self, aura, beam, body, buff, item::Reagent, object, shockwave, BeamSegment, Body, - CharacterState, Shockwave, Vel, + CharacterState, Ori, Pos, Shockwave, Vel, }, figure::Segment, outcome::Outcome, @@ -763,13 +763,18 @@ impl ParticleMgr { let time = state.get_time(); let dt = scene_data.state.ecs().fetch::().0; - for (interpolated, beam) in ( - &ecs.read_storage::(), + for (interp, pos, ori, beam) in ( + ecs.read_storage::().maybe(), + &ecs.read_storage::(), + &ecs.read_storage::(), &ecs.read_storage::(), ) .join() - .filter(|(_, b)| b.creation.map_or(true, |c| (c + dt as f64) >= time)) + .filter(|(_, _, _, b)| b.creation.map_or(true, |c| (c + dt as f64) >= time)) { + let pos = interp.map_or(pos.0, |i| i.pos); + let ori = interp.map_or(*ori, |i| i.ori); + // TODO: Handle this less hackily. Done this way as beam segments are created // every server tick, which is approximately 33 ms. Heartbeat scheduler used to // account for clients with less than 30 fps because they start the creation @@ -779,11 +784,11 @@ impl ParticleMgr { match beam.properties.specifier { beam::FrontendSpecifier::Flamethrower => { let mut rng = thread_rng(); - let (from, to) = (Vec3::::unit_z(), *interpolated.ori.look_dir()); + let (from, to) = (Vec3::::unit_z(), *ori.look_dir()); let m = Mat3::::rotation_from_to_3d(from, to); // Emit a light when using flames lights.push(Light::new( - interpolated.pos, + pos, Rgb::new(1.0, 0.25, 0.05).map(|e| e * rng.gen_range(0.8..1.2)), 2.0, )); @@ -802,19 +807,19 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::FlameThrower, - interpolated.pos, - interpolated.pos + random_ori * range, + pos, + pos + random_ori * range, ) }, ); }, beam::FrontendSpecifier::Cultist => { let mut rng = thread_rng(); - let (from, to) = (Vec3::::unit_z(), *interpolated.ori.look_dir()); + let (from, to) = (Vec3::::unit_z(), *ori.look_dir()); let m = Mat3::::rotation_from_to_3d(from, to); // Emit a light when using flames lights.push(Light::new( - interpolated.pos, + pos, Rgb::new(1.0, 0.0, 1.0).map(|e| e * rng.gen_range(0.5..1.0)), 2.0, )); @@ -833,23 +838,23 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::CultistFlame, - interpolated.pos, - interpolated.pos + random_ori * range, + pos, + pos + random_ori * range, ) }, ); }, beam::FrontendSpecifier::LifestealBeam => { // Emit a light when using lifesteal beam - lights.push(Light::new(interpolated.pos, Rgb::new(0.8, 1.0, 0.5), 1.0)); + lights.push(Light::new(pos, Rgb::new(0.8, 1.0, 0.5), 1.0)); self.particles.reserve(beam_tick_count as usize); for i in 0..beam_tick_count { self.particles.push(Particle::new_directed( beam.properties.duration, time + i as f64 / 1000.0, ParticleMode::LifestealBeam, - interpolated.pos, - interpolated.pos + *interpolated.ori.look_dir() * range, + pos, + pos + *ori.look_dir() * range, )); } }, @@ -859,8 +864,8 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::Laser, - interpolated.pos, - interpolated.pos + *interpolated.ori.look_dir() * range, + pos, + pos + *ori.look_dir() * range, ) }) }, @@ -870,14 +875,14 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::WebStrand, - interpolated.pos, - interpolated.pos + *interpolated.ori.look_dir() * range, + pos, + pos + *ori.look_dir() * range, ) }) }, beam::FrontendSpecifier::Bubbles => { let mut rng = thread_rng(); - let (from, to) = (Vec3::::unit_z(), *interpolated.ori.look_dir()); + let (from, to) = (Vec3::::unit_z(), *ori.look_dir()); let m = Mat3::::rotation_from_to_3d(from, to); self.particles.resize_with( self.particles.len() + usize::from(beam_tick_count) / 15, @@ -894,15 +899,15 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::Bubbles, - interpolated.pos, - interpolated.pos + random_ori * range, + pos, + pos + random_ori * range, ) }, ); }, beam::FrontendSpecifier::Frost => { let mut rng = thread_rng(); - let (from, to) = (Vec3::::unit_z(), *interpolated.ori.look_dir()); + let (from, to) = (Vec3::::unit_z(), *ori.look_dir()); let m = Mat3::::rotation_from_to_3d(from, to); self.particles.resize_with( self.particles.len() + usize::from(beam_tick_count) / 4, @@ -919,8 +924,8 @@ impl ParticleMgr { beam.properties.duration, time, ParticleMode::Ice, - interpolated.pos, - interpolated.pos + random_ori * range, + pos, + pos + random_ori * range, ) }, ); @@ -936,12 +941,15 @@ impl ParticleMgr { let mut rng = thread_rng(); let dt = scene_data.state.get_delta_time(); - for (interpolated, auras) in ( - &ecs.read_storage::(), + for (interp, pos, auras) in ( + ecs.read_storage::().maybe(), + &ecs.read_storage::(), &ecs.read_storage::(), ) .join() { + let pos = interp.map_or(pos.0, |i| i.pos); + for (_, aura) in auras.auras.iter() { match aura.aura_kind { aura::AuraKind::Buff { @@ -960,8 +968,8 @@ impl ParticleMgr { aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), time, ParticleMode::EnergyNature, - interpolated.pos, - interpolated.pos + init_pos, + pos, + pos + init_pos, ) }, ); @@ -992,8 +1000,8 @@ impl ParticleMgr { aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), time, ParticleMode::EnergyHealing, - interpolated.pos, - interpolated.pos + init_pos, + pos, + pos + init_pos, ) }, ); @@ -1016,15 +1024,15 @@ impl ParticleMgr { let radius = aura.radius * rng.gen::().sqrt(); let x = radius * theta.sin(); let y = radius * theta.cos(); - Vec2::new(x, y) + interpolated.pos.xy() + Vec2::new(x, y) + pos.xy() }; let max_dur = Duration::from_secs(1); Particle::new_directed( aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), time, ParticleMode::FlameThrower, - rand_pos.with_z(interpolated.pos.z), - rand_pos.with_z(interpolated.pos.z + 1.0), + rand_pos.with_z(pos.z), + rand_pos.with_z(pos.z + 1.0), ) }); }, @@ -1044,8 +1052,8 @@ impl ParticleMgr { aura.duration.map_or(max_dur, |dur| dur.min(max_dur)), time, ParticleMode::EnergyBuffing, - interpolated.pos, - interpolated.pos + init_pos, + pos, + pos + init_pos, ) }, ); @@ -1062,13 +1070,16 @@ impl ParticleMgr { let time = state.get_time(); let mut rng = rand::thread_rng(); - for (interpolated, buffs, body) in ( - &ecs.read_storage::(), + for (interp, pos, buffs, body) in ( + ecs.read_storage::().maybe(), + &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), ) .join() { + let pos = interp.map_or(pos.0, |i| i.pos); + for (buff_kind, _) in buffs.kinds.iter() { use buff::BuffKind; match buff_kind { @@ -1077,7 +1088,7 @@ impl ParticleMgr { self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(15))), || { - let start_pos = interpolated.pos + let start_pos = pos + Vec3::unit_z() * body.height() * 0.25 + Vec3::::zero() .map(|_| rng.gen_range(-1.0..1.0)) @@ -1107,7 +1118,7 @@ impl ParticleMgr { self.particles.len() + usize::from(self.scheduler.heartbeats(Duration::from_millis(15))), || { - let start_pos = interpolated.pos + let start_pos = pos + Vec3::new( body.max_radius(), body.max_radius(), @@ -1361,13 +1372,18 @@ impl ParticleMgr { let dt = scene_data.state.ecs().fetch::().0; let terrain = scene_data.state.ecs().fetch::(); - for (_entity, interpolated, shockwave) in ( + for (_entity, interp, pos, ori, shockwave) in ( &ecs.entities(), - &ecs.read_storage::(), + ecs.read_storage::().maybe(), + &ecs.read_storage::(), + &ecs.read_storage::(), &ecs.read_storage::(), ) .join() { + let pos = interp.map_or(pos.0, |i| i.pos); + let ori = interp.map_or(*ori, |i| i.ori); + let elapsed = time - shockwave.creation.unwrap_or(time); let speed = shockwave.properties.speed; @@ -1377,7 +1393,7 @@ impl ParticleMgr { let radians = shockwave.properties.angle.to_radians(); - let ori_vec = interpolated.ori.look_vec(); + let ori_vec = ori.look_vec(); let theta = ori_vec.y.atan2(ori_vec.x) - radians / 2.0; let dtheta = radians / distance; @@ -1406,7 +1422,7 @@ impl ParticleMgr { for d in 0..(new_particle_count as i32) { let arc_position = theta + dtheta * d as f32 / particle_count_factor; - let position = interpolated.pos + let position = pos + distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0); // Arbitrary number chosen that is large enough to be able to accurately @@ -1456,7 +1472,7 @@ impl ParticleMgr { for d in 0..3 * distance as i32 { let arc_position = theta + dtheta * d as f32 / 3.0; - let position = interpolated.pos + let position = pos + distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0); self.particles.push(Particle::new( @@ -1489,7 +1505,7 @@ impl ParticleMgr { // Sub tick dt let dt = (j as f32 / heartbeats as f32) * dt; let distance = distance + speed * dt; - let pos1 = interpolated.pos + distance * direction - Vec3::unit_z(); + let pos1 = pos + distance * direction - Vec3::unit_z(); let pos2 = pos1 + (Vec3::unit_z() + direction) * 3.0; let time = time + dt as f64; @@ -1532,8 +1548,7 @@ impl ParticleMgr { // Sub tick dt let dt = (j as f32 / heartbeats as f32) * dt; let scaled_distance = scaled_distance + scaled_speed * dt; - let pos1 = - interpolated.pos + (scaled_distance * direction).floor() * scale; + let pos1 = pos + (scaled_distance * direction).floor() * scale; let time = time + dt as f64; let get_positions = |a| { diff --git a/world/src/layer/cave.rs b/world/src/layer/cave.rs index edc1423379..3e536dc521 100644 --- a/world/src/layer/cave.rs +++ b/world/src/layer/cave.rs @@ -695,7 +695,7 @@ fn write_column( * bridge) as i32) .min(h - 2) && z < bedrock + h - && radius > 30.0 + && radius > 25.0 } { Block::new(BlockKind::Rock, col.stone_col) } else {