mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Interpolate in client
This commit is contained in:
parent
48117988e1
commit
b578f0231f
@ -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"),
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -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>) {
|
||||
|
@ -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());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user