Interpolate in client

This commit is contained in:
IsseW 2022-03-15 20:26:27 +01:00
parent 48117988e1
commit b578f0231f
5 changed files with 110 additions and 98 deletions

View File

@ -107,7 +107,6 @@ pub enum Event {
CharacterEdited(CharacterId),
CharacterError(String),
MapMarker(comp::MapMarkerUpdate),
WeatherUpdate,
}
pub struct WorldData {
@ -153,13 +152,60 @@ pub struct SiteInfoRich {
pub economy: Option<EconomyInfo>,
}
struct WeatherLerp {
old: (Grid<Weather>, Instant),
new: (Grid<Weather>, Instant),
current: Grid<Weather>,
}
impl WeatherLerp {
fn weather_update(&mut self, weather: Grid<Weather>) {
self.old = mem::replace(&mut self.new, (weather, Instant::now()));
}
fn update(&mut self) {
let old = &self.old.0;
let new = &self.new.0;
if old.size() != new.size() {
if self.current.size() != new.size() {
self.current = new.clone();
}
} else {
// Assume updates are regular
let t = (self.new.1.elapsed().as_secs_f32()
/ self.new.1.duration_since(self.old.1).as_secs_f32())
.clamp(0.0, 1.0);
old.iter().zip(new.iter()).for_each(|((p, old), (_, new))| {
self.current[p] = Weather::lerp(old, new, t);
});
}
}
}
impl Default for WeatherLerp {
fn default() -> Self {
Self {
old: (
Grid::new(Vec2::new(0, 0), Weather::default()),
Instant::now(),
),
new: (
Grid::new(Vec2::new(0, 0), Weather::default()),
Instant::now(),
),
current: Grid::new(Vec2::new(0, 0), Weather::default()),
}
}
}
pub struct Client {
registered: bool,
presence: Option<PresenceKind>,
runtime: Arc<Runtime>,
server_info: ServerInfo,
world_data: WorldData,
weather: Grid<Weather>,
weather: WeatherLerp,
player_list: HashMap<Uid, PlayerInfo>,
character_list: CharacterList,
sites: HashMap<SiteId, SiteInfoRich>,
@ -611,7 +657,7 @@ impl Client {
lod_horizon,
map: world_map,
},
weather: Grid::new(Vec2::new(1, 1), Weather::default()),
weather: WeatherLerp::default(),
player_list: HashMap::new(),
character_list: CharacterList::default(),
sites: sites
@ -1417,23 +1463,45 @@ impl Client {
.map(|v| v.0)
}
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather }
pub fn get_weather(&self) -> &Grid<Weather> { &self.weather.current }
pub fn current_weather(&self) -> Weather {
if let Some(position) = self.position() {
let cell_pos = (position.xy()
/ ((TerrainChunkSize::RECT_SIZE * weather::CHUNKS_PER_CELL).as_()))
.as_();
*self.weather.get(cell_pos).unwrap_or(&Weather::default())
} else {
Weather::default()
}
self.position()
.map(|wpos| self.current_weather_wpos(wpos.xy()))
.unwrap_or_default()
}
pub fn current_weather_wpos(&self, wpos: Vec2<f32>) -> Weather {
let cell_pos =
(wpos / ((TerrainChunkSize::RECT_SIZE * weather::CHUNKS_PER_CELL).as_())).as_();
*self.weather.get(cell_pos).unwrap_or(&Weather::default())
let cell_pos = wpos / ((TerrainChunkSize::RECT_SIZE * weather::CHUNKS_PER_CELL).as_());
let rpos = cell_pos.map(|e| e.fract());
let cell_pos = cell_pos.map(|e| e.floor());
let wpos = cell_pos.as_::<i32>();
Weather::lerp(
&Weather::lerp(
self.weather
.current
.get(wpos)
.unwrap_or(&Weather::default()),
self.weather
.current
.get(wpos + Vec2::unit_x())
.unwrap_or(&Weather::default()),
rpos.x,
),
&Weather::lerp(
self.weather
.current
.get(wpos + Vec2::unit_x())
.unwrap_or(&Weather::default()),
self.weather
.current
.get(wpos + Vec2::one())
.unwrap_or(&Weather::default()),
rpos.x,
),
rpos.y,
)
}
pub fn current_chunk(&self) -> Option<Arc<TerrainChunk>> {
@ -1681,6 +1749,8 @@ impl Client {
// 5) Terrain
self.tick_terrain()?;
// TODO: put this somewhere else?
self.weather.update();
// Send a ping to the server once every second
if self.state.get_time() - self.last_server_ping > 1. {
@ -2217,8 +2287,7 @@ impl Client {
frontend_events.push(Event::MapMarker(event));
},
ServerGeneral::WeatherUpdate(weather) => {
self.weather = weather;
frontend_events.push(Event::WeatherUpdate);
self.weather.weather_update(weather);
},
_ => unreachable!("Not a in_game message"),
}

View File

@ -1,7 +1,6 @@
use super::super::{AaMode, GlobalsLayouts, Renderer, Texture, Vertex as VertexTrait};
use bytemuck::{Pod, Zeroable};
use common::{grid::Grid, weather::Weather};
use std::{mem, time::Instant};
use std::mem;
use vek::*;
#[repr(C)]
@ -32,77 +31,12 @@ impl VertexTrait for Vertex {
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
}
pub struct WeatherTexture {
a: (Grid<Weather>, Instant),
b: (Grid<Weather>, Instant),
pub tex: Texture,
}
impl WeatherTexture {
fn new(tex: Texture) -> Self {
Self {
a: (Grid::new(Vec2::zero(), Default::default()), Instant::now()),
b: (Grid::new(Vec2::zero(), Default::default()), Instant::now()),
tex,
}
}
pub fn update_weather(&mut self, weather: Grid<Weather>) {
self.a = mem::replace(&mut self.b, (weather, Instant::now()));
}
pub fn update_texture(&self, renderer: &mut Renderer) {
let a = &self.a.0;
let b = &self.b.0;
let size = self.b.0.size().as_::<u32>();
if a.size() != b.size() {
renderer.update_texture(
&self.tex,
[0, 0],
[size.x, size.y],
&b.iter()
.map(|(_, w)| {
[
(w.cloud * 255.0) as u8,
(w.rain * 255.0) as u8,
(w.wind.x + 128.0).clamp(0.0, 255.0) as u8,
(w.wind.y + 128.0).clamp(0.0, 255.0) as u8,
]
})
.collect::<Vec<_>>(),
);
} else {
// Assume updates are regular
let t = (self.b.1.elapsed().as_secs_f32()
/ self.b.1.duration_since(self.a.1).as_secs_f32())
.clamp(0.0, 1.0);
renderer.update_texture(
&self.tex,
[0, 0],
[size.x, size.y],
&a.iter()
.zip(b.iter())
.map(|((_, a), (_, b))| {
let w = Weather::lerp(a, b, t);
[
(w.cloud * 255.0) as u8,
(w.rain * 255.0) as u8,
(w.wind.x + 128.0).clamp(0.0, 255.0) as u8,
(w.wind.y + 128.0).clamp(0.0, 255.0) as u8,
]
})
.collect::<Vec<_>>(),
);
}
}
}
pub struct LodData {
pub map: Texture,
pub alt: Texture,
pub horizon: Texture,
pub tgt_detail: u32,
pub weather: WeatherTexture,
pub weather: Texture,
}
impl LodData {
@ -251,7 +185,7 @@ impl LodData {
alt,
horizon,
tgt_detail,
weather: WeatherTexture::new(weather),
weather,
}
}
}

View File

@ -578,11 +578,11 @@ impl GlobalsLayouts {
},
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::TextureView(&lod_data.weather.tex.view),
resource: wgpu::BindingResource::TextureView(&lod_data.weather.view),
},
wgpu::BindGroupEntry {
binding: 13,
resource: wgpu::BindingResource::Sampler(&lod_data.weather.tex.sampler),
resource: wgpu::BindingResource::Sampler(&lod_data.weather.sampler),
},
]
}

View File

@ -10,11 +10,9 @@ use crate::{
use client::Client;
use common::{
assets::{AssetExt, ObjAsset},
grid::Grid,
lod,
spiral::Spiral2d,
util::srgba_to_linear,
weather::Weather,
};
use hashbrown::HashMap;
use std::ops::Range;
@ -79,10 +77,6 @@ impl Lod {
pub fn get_data(&self) -> &LodData { &self.data }
pub fn update_weather(&mut self, weather: Grid<Weather>) {
self.data.weather.update_weather(weather);
}
pub fn set_detail(&mut self, detail: u32) {
// Make sure the recorded detail is even.
self.data.tgt_detail = (detail - detail % 2).max(100).min(2500);
@ -95,7 +89,6 @@ impl Lod {
focus_pos: Vec3<f32>,
camera: &Camera,
) {
self.data.weather.update_texture(renderer);
// Update LoD terrain mesh according to detail
if self
.model
@ -188,6 +181,25 @@ impl Lod {
}
}
}
// Update weather texture
let weather = client.get_weather();
let size = weather.size().as_::<u32>();
renderer.update_texture(
&self.data.weather,
[0, 0],
[size.x, size.y],
&weather
.iter()
.map(|(_, w)| {
[
(w.cloud * 255.0) as u8,
(w.rain * 255.0) as u8,
(w.wind.x + 128.0).clamp(0.0, 255.0) as u8,
(w.wind.y + 128.0).clamp(0.0, 255.0) as u8,
]
})
.collect::<Vec<_>>(),
);
}
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) {

View File

@ -324,9 +324,6 @@ impl SessionState {
client::Event::MapMarker(event) => {
self.hud.show.update_map_markers(event);
},
client::Event::WeatherUpdate => {
self.scene.lod.update_weather(client.get_weather().clone());
},
}
}