Began using Grid<T> for LoD data

This commit is contained in:
Joshua Barretto 2020-11-25 14:59:28 +00:00
parent 20b45a1202
commit e5ebbd31fa
7 changed files with 61 additions and 22 deletions

View File

@ -24,6 +24,7 @@ use common::{
InventoryManip, InventoryUpdateEvent, InventoryManip, InventoryUpdateEvent,
}, },
event::{EventBus, LocalEvent}, event::{EventBus, LocalEvent},
grid::Grid,
msg::{ msg::{
validate_chat_msg, world_msg::SiteInfo, ChatMsgValidationError, ClientGeneral, ClientMsg, validate_chat_msg, world_msg::SiteInfo, ChatMsgValidationError, ClientGeneral, ClientMsg,
ClientRegister, ClientType, DisconnectReason, InviteAnswer, Notification, PingMsg, ClientRegister, ClientType, DisconnectReason, InviteAnswer, Notification, PingMsg,
@ -80,15 +81,15 @@ pub struct Client {
/// Just the "base" layer for LOD; currently includes colors and nothing /// Just the "base" layer for LOD; currently includes colors and nothing
/// else. In the future we'll add more layers, like shadows, rivers, and /// else. In the future we'll add more layers, like shadows, rivers, and
/// probably foliage, cities, roads, and other structures. /// probably foliage, cities, roads, and other structures.
pub lod_base: Vec<u32>, pub lod_base: Grid<u32>,
/// The "height" layer for LOD; currently includes only land altitudes, but /// The "height" layer for LOD; currently includes only land altitudes, but
/// in the future should also water depth, and probably other /// in the future should also water depth, and probably other
/// information as well. /// information as well.
pub lod_alt: Vec<u32>, pub lod_alt: Grid<u32>,
/// The "shadow" layer for LOD. Includes east and west horizon angles and /// The "shadow" layer for LOD. Includes east and west horizon angles and
/// an approximate max occluder height, which we use to try to /// an approximate max occluder height, which we use to try to
/// approximate soft and volumetric shadows. /// approximate soft and volumetric shadows.
pub lod_horizon: Vec<u32>, pub lod_horizon: Grid<u32>,
/// A fully rendered map image for use with the map and minimap; note that /// A fully rendered map image for use with the map and minimap; note that
/// this can be constructed dynamically by combining the layers of world /// this can be constructed dynamically by combining the layers of world
/// map data (e.g. with shadow map data or river data), but at present /// map data (e.g. with shadow map data or river data), but at present
@ -229,11 +230,10 @@ impl Client {
let sea_level = world_map.sea_level; let sea_level = world_map.sea_level;
let rgba = world_map.rgba; let rgba = world_map.rgba;
let alt = world_map.alt; let alt = world_map.alt;
let expected_size = (u32::from(map_size.x) * u32::from(map_size.y)) as usize; if rgba.size() != map_size.map(|e| e as i32) {
if rgba.len() != expected_size {
return Err(Error::Other("Server sent a bad world map image".into())); return Err(Error::Other("Server sent a bad world map image".into()));
} }
if alt.len() != expected_size { if rgba.size() != map_size.map(|e| e as i32) {
return Err(Error::Other("Server sent a bad altitude map.".into())); return Err(Error::Other("Server sent a bad altitude map.".into()));
} }
let [west, east] = world_map.horizons; let [west, east] = world_map.horizons;
@ -257,7 +257,7 @@ impl Client {
let horizons = [unzip_horizons(&west), unzip_horizons(&east)]; let horizons = [unzip_horizons(&west), unzip_horizons(&east)];
// Redraw map (with shadows this time). // Redraw map (with shadows this time).
let mut world_map_rgba = vec![0u32; rgba.len()]; let mut world_map_rgba = vec![0u32; rgba.size().product() as usize];
let mut map_config = common::terrain::map::MapConfig::orthographic( let mut map_config = common::terrain::map::MapConfig::orthographic(
map_size_lg, map_size_lg,
core::ops::RangeInclusive::new(0.0, max_height), core::ops::RangeInclusive::new(0.0, max_height),
@ -274,14 +274,14 @@ impl Client {
|pos| { |pos| {
let (rgba, alt, downhill_wpos) = if bounds_check(pos) { let (rgba, alt, downhill_wpos) = if bounds_check(pos) {
let posi = pos.y as usize * map_size.x as usize + pos.x as usize; let posi = pos.y as usize * map_size.x as usize + pos.x as usize;
let [r, g, b, a] = rgba[posi].to_le_bytes(); let [r, g, b, a] = rgba[pos].to_le_bytes();
let alti = alt[posi]; let alti = alt[pos];
// Compute downhill. // Compute downhill.
let downhill = { let downhill = {
let mut best = -1; let mut best = -1;
let mut besth = alti; let mut besth = alti;
for nposi in neighbors(map_size_lg, posi) { for nposi in neighbors(map_size_lg, posi) {
let nbh = alt[nposi]; let nbh = alt.raw()[nposi];
if nbh < besth { if nbh < besth {
besth = nbh; besth = nbh;
best = nposi as isize; best = nposi as isize;
@ -317,8 +317,7 @@ impl Client {
|wpos| { |wpos| {
let pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, f| e / f as i32); let pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, f| e / f as i32);
rescale_height(if bounds_check(pos) { rescale_height(if bounds_check(pos) {
let posi = pos.y as usize * map_size.x as usize + pos.x as usize; scale_height_big(alt[pos])
scale_height_big(alt[posi])
} else { } else {
0.0 0.0
}) })
@ -361,7 +360,7 @@ impl Client {
entity, entity,
lod_base, lod_base,
lod_alt, lod_alt,
lod_horizon, Grid::from_raw(map_size.map(|e| e as i32), lod_horizon),
(world_map_img, map_size, map_bounds), (world_map_img, map_size, map_bounds),
world_map.sites, world_map.sites,
recipe_book, recipe_book,

View File

@ -1,11 +1,20 @@
use serde::{Deserialize, Serialize};
use std::ops::{Index, IndexMut};
use vek::*; use vek::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Grid<T> { pub struct Grid<T> {
cells: Vec<T>, cells: Vec<T>,
size: Vec2<i32>, size: Vec2<i32>,
} }
impl<T> Grid<T> { impl<T> Grid<T> {
pub fn from_raw(size: Vec2<i32>, raw: impl Into<Vec<T>>) -> Self {
let cells = raw.into();
assert_eq!(size.product() as usize, cells.len());
Self { cells, size }
}
pub fn populate_from(size: Vec2<i32>, mut f: impl FnMut(Vec2<i32>) -> T) -> Self { pub fn populate_from(size: Vec2<i32>, mut f: impl FnMut(Vec2<i32>) -> T) -> Self {
Self { Self {
cells: (0..size.y) cells: (0..size.y)
@ -81,4 +90,32 @@ impl<T> Grid<T> {
}) })
.flatten() .flatten()
} }
pub fn raw(&self) -> &[T] { &self.cells }
}
impl<T> Index<Vec2<i32>> for Grid<T> {
type Output = T;
fn index(&self, index: Vec2<i32>) -> &Self::Output {
self.get(index).unwrap_or_else(|| {
panic!(
"Attempted to index grid of size {:?} with index {:?}",
self.size(),
index
)
})
}
}
impl<T> IndexMut<Vec2<i32>> for Grid<T> {
fn index_mut(&mut self, index: Vec2<i32>) -> &mut Self::Output {
let size = self.size();
self.get_mut(index).unwrap_or_else(|| {
panic!(
"Attempted to index grid of size {:?} with index {:?}",
size, index
)
})
}
} }

View File

@ -30,6 +30,7 @@ pub mod event;
pub mod explosion; pub mod explosion;
pub mod figure; pub mod figure;
pub mod generation; pub mod generation;
pub mod grid;
pub mod loadout_builder; pub mod loadout_builder;
pub mod lottery; pub mod lottery;
pub mod metrics; pub mod metrics;

View File

@ -1,3 +1,4 @@
use crate::grid::Grid;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use vek::*; use vek::*;
@ -30,12 +31,12 @@ pub struct WorldMapMsg {
pub max_height: f32, pub max_height: f32,
/// RGB+A; the alpha channel is currently unused, but will be used in the /// RGB+A; the alpha channel is currently unused, but will be used in the
/// future. Entries are in the usual chunk order. /// future. Entries are in the usual chunk order.
pub rgba: Vec<u32>, pub rgba: Grid<u32>,
/// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for /// Altitudes: bits 2 to 0 are unused, then bits 15 to 3 are used for
/// altitude. The remainder are currently unused, but we have plans to /// altitude. The remainder are currently unused, but we have plans to
/// use 7 bits for water depth (using an integer f7 encoding), and we /// use 7 bits for water depth (using an integer f7 encoding), and we
/// will find other uses for the remaining 12 bits. /// will find other uses for the remaining 12 bits.
pub alt: Vec<u32>, pub alt: Grid<u32>,
/// Horizon mapping. This is a variant of shadow mapping that is /// Horizon mapping. This is a variant of shadow mapping that is
/// specifically designed for height maps; it takes advantage of their /// specifically designed for height maps; it takes advantage of their
/// regular structure (e.g. no holes) to compress all information needed /// regular structure (e.g. no holes) to compress all information needed

View File

@ -29,9 +29,9 @@ impl Lod {
data: LodData::new( data: LodData::new(
renderer, renderer,
client.world_map.1, client.world_map.1,
&client.lod_base, &client.lod_base.raw(),
&client.lod_alt, &client.lod_alt.raw(),
&client.lod_horizon, &client.lod_horizon.raw(),
settings.graphics.lod_detail.max(100).min(2500), settings.graphics.lod_detail.max(100).min(2500),
water_color().into_array().into(), water_color().into_array().into(),
), ),

View File

@ -36,6 +36,7 @@ use crate::{
}; };
use common::{ use common::{
assets, assets,
grid::Grid,
msg::WorldMapMsg, msg::WorldMapMsg,
store::Id, store::Id,
terrain::{ terrain::{
@ -1498,8 +1499,8 @@ impl WorldSim {
dimensions_lg: self.map_size_lg().vec(), dimensions_lg: self.map_size_lg().vec(),
sea_level: CONFIG.sea_level, sea_level: CONFIG.sea_level,
max_height: self.max_height, max_height: self.max_height,
rgba: v, rgba: Grid::from_raw(self.get_size().map(|e| e as i32), v),
alt: alts, alt: Grid::from_raw(self.get_size().map(|e| e as i32), alts),
horizons, horizons,
sites: Vec::new(), // Will be substituted later sites: Vec::new(), // Will be substituted later
} }

View File

@ -1,5 +1,4 @@
pub mod fast_noise; pub mod fast_noise;
pub mod grid;
pub mod map_vec; pub mod map_vec;
pub mod random; pub mod random;
pub mod sampler; pub mod sampler;
@ -11,7 +10,6 @@ pub mod unit_chooser;
// Reexports // Reexports
pub use self::{ pub use self::{
fast_noise::FastNoise, fast_noise::FastNoise,
grid::Grid,
map_vec::MapVec, map_vec::MapVec,
random::{RandomField, RandomPerm}, random::{RandomField, RandomPerm},
sampler::{Sampler, SamplerMut}, sampler::{Sampler, SamplerMut},
@ -20,6 +18,8 @@ pub use self::{
unit_chooser::UnitChooser, unit_chooser::UnitChooser,
}; };
pub use common::grid::Grid;
use fxhash::FxHasher32; use fxhash::FxHasher32;
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;