mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
common: Rework volume API
See the doc comments in `common/src/vol.rs` for more information on the API itself. The changes include: * Consistent `Err`/`Error` naming. * Types are named `...Error`. * `enum` variants are named `...Err`. * Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation to an upcoming change where a “map” in the game related sense will be added. * Add volume iterators. There are two types of them: * _Position_ iterators obtained from the trait `IntoPosIterator` using the method `fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `Vec3<i32>`. * _Volume_ iterators obtained from the trait `IntoVolIterator` using the method `fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...` which returns an iterator over `(Vec3<i32>, &Self::Vox)`. Those traits will usually be implemented by references to volume types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some type which usually implements several volume traits, such as `Chunk`). * _Position_ iterators iterate over the positions valid for that volume. * _Volume_ iterators do the same but return not only the position but also the voxel at that position, in each iteration. * Introduce trait `RectSizedVol` for the use case which we have with `Chonk`: A `Chonk` is sized only in x and y direction. * Introduce traits `RasterableVol`, `RectRasterableVol` * `RasterableVol` represents a volume that is compile-time sized and has its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen because such a volume can be used with `VolGrid3d`. * `RectRasterableVol` represents a volume that is compile-time sized at least in x and y direction and has its lower bound at `(0, 0, z)`. There's no requirement on he lower bound or size in z direction. The name `RectRasterableVol` was chosen because such a volume can be used with `VolGrid2d`.
This commit is contained in:
parent
886d554f52
commit
1796c09ca1
@ -13,7 +13,7 @@ use common::{
|
||||
net::PostBox,
|
||||
state::{State, Uid},
|
||||
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
vol::RectVolSize,
|
||||
ChatType,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
@ -210,7 +210,7 @@ impl Client {
|
||||
.cloned()?
|
||||
.0,
|
||||
)
|
||||
.map2(Vec2::from(TerrainChunkSize::SIZE), |e: f32, sz| {
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e: f32, sz| {
|
||||
(e as u32).div_euclid(sz) as i32
|
||||
});
|
||||
|
||||
|
@ -5,7 +5,7 @@ pub use mat_cell::Material;
|
||||
use self::cell::Cell;
|
||||
use self::mat_cell::MatCell;
|
||||
use crate::{
|
||||
vol::{ReadVol, SizedVol, Vox, WriteVol},
|
||||
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
|
||||
volumes::dyna::Dyna,
|
||||
};
|
||||
use dot_vox::DotVoxData;
|
||||
@ -52,7 +52,7 @@ impl From<&DotVoxData> for Segment {
|
||||
impl Segment {
|
||||
/// Transform cells
|
||||
pub fn map(mut self, transform: impl Fn(Cell) -> Option<Cell>) -> Self {
|
||||
for pos in self.iter_positions() {
|
||||
for pos in self.full_pos_iter() {
|
||||
if let Some(new) = transform(*self.get(pos).unwrap()) {
|
||||
self.set(pos, new).unwrap();
|
||||
}
|
||||
@ -91,9 +91,9 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
|
||||
|
||||
// Determine size of the new Dyna
|
||||
let mut min_point = self.0[0].1;
|
||||
let mut max_point = self.0[0].1 + self.0[0].0.get_size().map(|e| e as i32);
|
||||
let mut max_point = self.0[0].1 + self.0[0].0.size().map(|e| e as i32);
|
||||
for (dyna, offset) in self.0.iter().skip(1) {
|
||||
let size = dyna.get_size().map(|e| e as i32);
|
||||
let size = dyna.size().map(|e| e as i32);
|
||||
min_point = min_point.map2(*offset, std::cmp::min);
|
||||
max_point = max_point.map2(offset + size, std::cmp::max);
|
||||
}
|
||||
@ -103,8 +103,7 @@ impl<V: Vox + Copy> DynaUnionizer<V> {
|
||||
// Copy segments into combined
|
||||
let origin = min_point.map(|e| e * -1);
|
||||
for (dyna, offset) in self.0 {
|
||||
for pos in dyna.iter_positions() {
|
||||
let vox = dyna.get(pos).unwrap();
|
||||
for (pos, vox) in dyna.full_vol_iter() {
|
||||
if !vox.is_empty() {
|
||||
combined.set(origin + offset + pos, *vox).unwrap();
|
||||
}
|
||||
@ -119,9 +118,9 @@ pub type MatSegment = Dyna<MatCell, ()>;
|
||||
|
||||
impl MatSegment {
|
||||
pub fn to_segment(&self, map: impl Fn(Material) -> Rgb<u8>) -> Segment {
|
||||
let mut vol = Dyna::filled(self.get_size(), Cell::empty(), ());
|
||||
for pos in self.iter_positions() {
|
||||
let rgb = match self.get(pos).unwrap() {
|
||||
let mut vol = Dyna::filled(self.size(), Cell::empty(), ());
|
||||
for (pos, vox) in self.full_vol_iter() {
|
||||
let rgb = match vox {
|
||||
MatCell::None => continue,
|
||||
MatCell::Mat(mat) => map(*mat),
|
||||
MatCell::Normal(rgb) => *rgb,
|
||||
|
@ -53,7 +53,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> Ray<'a, V, F, G> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Err>) {
|
||||
pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Error>) {
|
||||
// TODO: Fully test this!
|
||||
|
||||
const PLANCK: f32 = 0.001;
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
msg::{EcsCompPacket, EcsResPacket},
|
||||
sys,
|
||||
terrain::{Block, TerrainChunk, TerrainMap},
|
||||
terrain::{Block, TerrainChunk, TerrainGrid},
|
||||
vol::WriteVol,
|
||||
};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
@ -150,7 +150,7 @@ impl State {
|
||||
// Register unsynced resources used by the ECS.
|
||||
ecs.add_resource(Time(0.0));
|
||||
ecs.add_resource(DeltaTime(0.0));
|
||||
ecs.add_resource(TerrainMap::new().unwrap());
|
||||
ecs.add_resource(TerrainGrid::new().unwrap());
|
||||
ecs.add_resource(BlockChange::default());
|
||||
ecs.add_resource(TerrainChanges::default());
|
||||
ecs.add_resource(EventBus::<ServerEvent>::default());
|
||||
@ -217,12 +217,12 @@ impl State {
|
||||
}
|
||||
|
||||
/// Get a reference to this state's terrain.
|
||||
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
||||
pub fn terrain(&self) -> Fetch<TerrainGrid> {
|
||||
self.ecs.read_resource()
|
||||
}
|
||||
|
||||
/// Get a writable reference to this state's terrain.
|
||||
pub fn terrain_mut(&self) -> FetchMut<TerrainMap> {
|
||||
pub fn terrain_mut(&self) -> FetchMut<TerrainGrid> {
|
||||
self.ecs.write_resource()
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@ impl State {
|
||||
pub fn insert_chunk(&mut self, key: Vec2<i32>, chunk: TerrainChunk) {
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.write_resource::<TerrainGrid>()
|
||||
.insert(key, Arc::new(chunk))
|
||||
.is_some()
|
||||
{
|
||||
@ -268,7 +268,7 @@ impl State {
|
||||
pub fn remove_chunk(&mut self, key: Vec2<i32>) {
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.write_resource::<TerrainGrid>()
|
||||
.remove(key)
|
||||
.is_some()
|
||||
{
|
||||
@ -299,7 +299,7 @@ impl State {
|
||||
self.ecs.maintain();
|
||||
|
||||
// Apply terrain changes
|
||||
let mut terrain = self.ecs.write_resource::<TerrainMap>();
|
||||
let mut terrain = self.ecs.write_resource::<TerrainGrid>();
|
||||
self.ecs
|
||||
.read_resource::<BlockChange>()
|
||||
.blocks
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
Stats, Vel,
|
||||
},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use std::time::Duration;
|
||||
@ -30,7 +30,7 @@ pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, Controller>,
|
||||
|
@ -3,7 +3,7 @@ use {
|
||||
comp::{Body, Ori, PhysicsState, Pos, Scale, Vel},
|
||||
event::{EventBus, LocalEvent},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
terrain::TerrainGrid,
|
||||
vol::ReadVol,
|
||||
},
|
||||
specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage},
|
||||
@ -32,7 +32,7 @@ pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, TerrainMap>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
Read<'a, EventBus<LocalEvent>>,
|
||||
ReadStorage<'a, Scale>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{block::Block, TerrainChunkMeta, TerrainChunkSize};
|
||||
use crate::{
|
||||
vol::{BaseVol, ReadVol, VolSize, WriteVol},
|
||||
volumes::chunk::{Chunk, ChunkErr},
|
||||
vol::{BaseVol, ReadVol, RectRasterableVol, RectVolSize, VolSize, WriteVol},
|
||||
volumes::chunk::{Chunk, ChunkError},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@ -10,7 +10,7 @@ use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChonkError {
|
||||
ChunkError(ChunkErr),
|
||||
ChunkError(ChunkError),
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
@ -21,8 +21,8 @@ pub struct SubChunkSize;
|
||||
|
||||
impl VolSize for SubChunkSize {
|
||||
const SIZE: Vec3<u32> = Vec3 {
|
||||
x: TerrainChunkSize::SIZE.x,
|
||||
y: TerrainChunkSize::SIZE.y,
|
||||
x: TerrainChunkSize::RECT_SIZE.x,
|
||||
y: TerrainChunkSize::RECT_SIZE.y,
|
||||
z: SUB_CHUNK_HEIGHT,
|
||||
};
|
||||
}
|
||||
@ -111,7 +111,11 @@ impl Chonk {
|
||||
|
||||
impl BaseVol for Chonk {
|
||||
type Vox = Block;
|
||||
type Err = ChonkError;
|
||||
type Error = ChonkError;
|
||||
}
|
||||
|
||||
impl RectRasterableVol for Chonk {
|
||||
const RECT_SIZE: Vec2<u32> = TerrainChunkSize::RECT_SIZE;
|
||||
}
|
||||
|
||||
impl ReadVol for Chonk {
|
||||
|
@ -10,7 +10,7 @@ pub use self::{
|
||||
structure::Structure,
|
||||
};
|
||||
|
||||
use crate::{vol::VolSize, volumes::vol_map_2d::VolMap2d};
|
||||
use crate::{vol::RectVolSize, volumes::vol_grid_2d::VolGrid2d};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
@ -19,12 +19,8 @@ use vek::*;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TerrainChunkSize;
|
||||
|
||||
impl VolSize for TerrainChunkSize {
|
||||
const SIZE: Vec3<u32> = Vec3 {
|
||||
x: 32,
|
||||
y: 32,
|
||||
z: std::i32::MAX as u32,
|
||||
};
|
||||
impl RectVolSize for TerrainChunkSize {
|
||||
const RECT_SIZE: Vec2<u32> = Vec2 { x: 32, y: 32 };
|
||||
}
|
||||
|
||||
// TerrainChunkMeta
|
||||
@ -61,5 +57,5 @@ impl TerrainChunkMeta {
|
||||
|
||||
// Terrain type aliases
|
||||
|
||||
pub type TerrainChunk = chonk::Chonk; //Chunk<Block, TerrainChunkSize, TerrainChunkMeta>;
|
||||
pub type TerrainMap = VolMap2d<TerrainChunk, TerrainChunkSize>;
|
||||
pub type TerrainChunk = chonk::Chonk;
|
||||
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
||||
|
@ -2,14 +2,14 @@ use super::BlockKind;
|
||||
use crate::{
|
||||
assets::{self, Asset},
|
||||
vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol},
|
||||
volumes::dyna::{Dyna, DynaErr},
|
||||
volumes::dyna::{Dyna, DynaError},
|
||||
};
|
||||
use dot_vox::DotVoxData;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum StructureBlock {
|
||||
None,
|
||||
TemperateLeaves,
|
||||
@ -63,7 +63,7 @@ impl Structure {
|
||||
pub fn get_bounds(&self) -> Aabb<i32> {
|
||||
Aabb {
|
||||
min: -self.center,
|
||||
max: self.vol.get_size().map(|e| e as i32) - self.center,
|
||||
max: self.vol.size().map(|e| e as i32) - self.center,
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ impl Structure {
|
||||
|
||||
impl BaseVol for Structure {
|
||||
type Vox = StructureBlock;
|
||||
type Err = StructureError;
|
||||
type Error = StructureError;
|
||||
}
|
||||
|
||||
impl ReadVol for Structure {
|
||||
@ -82,7 +82,7 @@ impl ReadVol for Structure {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, StructureError> {
|
||||
match self.vol.get(pos + self.center) {
|
||||
Ok(block) => Ok(block),
|
||||
Err(DynaErr::OutOfBounds) => Ok(&self.empty),
|
||||
Err(DynaError::OutOfBounds) => Ok(&self.empty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,18 @@ use crate::ray::Ray;
|
||||
use std::fmt::Debug;
|
||||
use vek::*;
|
||||
|
||||
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics
|
||||
/// are implemented.
|
||||
pub trait VolSize: Clone {
|
||||
const SIZE: Vec3<u32>;
|
||||
}
|
||||
|
||||
pub trait RectVolSize: Clone {
|
||||
const RECT_SIZE: Vec2<u32>;
|
||||
}
|
||||
|
||||
/// A voxel.
|
||||
pub trait Vox: Sized {
|
||||
pub trait Vox: Sized + Clone + PartialEq {
|
||||
fn empty() -> Self;
|
||||
fn is_empty(&self) -> bool;
|
||||
|
||||
@ -19,64 +29,88 @@ pub trait Vox: Sized {
|
||||
/// A volume that contains voxel data.
|
||||
pub trait BaseVol {
|
||||
type Vox: Vox;
|
||||
type Err: Debug;
|
||||
type Error: Debug;
|
||||
}
|
||||
|
||||
/// Implementing `BaseVol` for any `&'a BaseVol` makes it possible to implement
|
||||
/// `IntoVolIterator` for references.
|
||||
impl<'a, T: BaseVol> BaseVol for &'a T {
|
||||
type Vox = T::Vox;
|
||||
type Error = T::Error;
|
||||
}
|
||||
|
||||
// Utility types
|
||||
|
||||
pub struct VoxPosIter {
|
||||
pos: Vec3<u32>,
|
||||
sz: Vec3<u32>,
|
||||
}
|
||||
/// A volume that is a cuboid.
|
||||
pub trait SizedVol: BaseVol {
|
||||
/// Returns the (inclusive) lower bound of the volume.
|
||||
fn lower_bound(&self) -> Vec3<i32>;
|
||||
|
||||
impl Iterator for VoxPosIter {
|
||||
type Item = Vec3<i32>;
|
||||
/// Returns the (exclusive) upper bound of the volume.
|
||||
fn upper_bound(&self) -> Vec3<i32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut old_pos = self.pos;
|
||||
|
||||
if old_pos.z == self.sz.z {
|
||||
old_pos.z = 0;
|
||||
old_pos.y += 1;
|
||||
if old_pos.y == self.sz.y {
|
||||
old_pos.y = 0;
|
||||
old_pos.x += 1;
|
||||
if old_pos.x == self.sz.x {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.pos = old_pos + Vec3::unit_z();
|
||||
|
||||
Some(old_pos.map(|e| e as i32))
|
||||
/// Returns the size of the volume.
|
||||
fn size(&self) -> Vec3<u32> {
|
||||
(self.upper_bound() - self.lower_bound()).map(|e| e as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that has a finite size.
|
||||
pub trait SizedVol: BaseVol {
|
||||
/// Get the size of the volume.
|
||||
fn get_size(&self) -> Vec3<u32>;
|
||||
/// A volume that is compile-time sized and has its lower bound at `(0, 0, 0)`.
|
||||
/// The name `RasterableVol` was chosen because such a volume can be used with
|
||||
/// `VolGrid3d`.
|
||||
pub trait RasterableVol: BaseVol {
|
||||
const SIZE: Vec3<u32>;
|
||||
}
|
||||
|
||||
/// Iterate through all potential voxel positions in this volume.
|
||||
fn iter_positions(&self) -> VoxPosIter {
|
||||
VoxPosIter {
|
||||
pos: Vec3::zero(),
|
||||
sz: self.get_size(),
|
||||
}
|
||||
impl<V: RasterableVol> SizedVol for V {
|
||||
fn lower_bound(&self) -> Vec3<i32> {
|
||||
Vec3::zero()
|
||||
}
|
||||
|
||||
fn upper_bound(&self) -> Vec3<i32> {
|
||||
V::SIZE.map(|e| e as i32)
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume whose cross section with the XY-plane is a rectangle.
|
||||
pub trait RectSizedVol: BaseVol {
|
||||
fn lower_bound_xy(&self) -> Vec2<i32>;
|
||||
|
||||
fn upper_bound_xy(&self) -> Vec2<i32>;
|
||||
|
||||
fn size_xy(&self) -> Vec2<u32> {
|
||||
(self.upper_bound_xy() - self.lower_bound_xy()).map(|e| e as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that is compile-time sized in x and y direction and has its lower
|
||||
/// bound at `(0, 0, z)`. In z direction there's no restriction on the lower
|
||||
/// or upper bound. The name `RectRasterableVol` was chosen because such a
|
||||
/// volume can be used with `VolGrid2d`.
|
||||
pub trait RectRasterableVol: BaseVol {
|
||||
const RECT_SIZE: Vec2<u32>;
|
||||
}
|
||||
|
||||
impl<V: RectRasterableVol> RectSizedVol for V {
|
||||
fn lower_bound_xy(&self) -> Vec2<i32> {
|
||||
Vec2::zero()
|
||||
}
|
||||
|
||||
fn upper_bound_xy(&self) -> Vec2<i32> {
|
||||
V::RECT_SIZE.map(|e| e as i32)
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that provides read access to its voxel data.
|
||||
pub trait ReadVol: BaseVol {
|
||||
/// Get a reference to the voxel at the provided position in the volume.
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||
fn get<'a>(&'a self, pos: Vec3<i32>) -> Result<&'a Self::Vox, Self::Error>;
|
||||
|
||||
fn ray(
|
||||
&self,
|
||||
fn ray<'a>(
|
||||
&'a self,
|
||||
from: Vec3<f32>,
|
||||
to: Vec3<f32>,
|
||||
) -> Ray<Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)>
|
||||
) -> Ray<'a, Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@ -85,6 +119,8 @@ pub trait ReadVol: BaseVol {
|
||||
}
|
||||
|
||||
/// A volume that provides the ability to sample (i.e., clone a section of) its voxel data.
|
||||
///
|
||||
/// TODO (haslersn): Do we still need this now that we have `IntoVolIterator`?
|
||||
pub trait SampleVol<I>: BaseVol {
|
||||
type Sample: BaseVol + ReadVol;
|
||||
/// Take a sample of the volume by cloning voxels within the provided range.
|
||||
@ -94,19 +130,142 @@ pub trait SampleVol<I>: BaseVol {
|
||||
///
|
||||
/// Note that the resultant volume has a coordinate space relative to the sample, not the
|
||||
/// original volume.
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, Self::Err>;
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, Self::Error>;
|
||||
}
|
||||
|
||||
/// A volume that provides write access to its voxel data.
|
||||
pub trait WriteVol: BaseVol {
|
||||
/// Set the voxel at the provided position in the volume to the provided value.
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err>;
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
// Utility traits
|
||||
/// A volume (usually rather a reference to a volume) that is convertible into
|
||||
/// an iterator to a cuboid subsection of the volume.
|
||||
pub trait IntoVolIterator<'a>: BaseVol
|
||||
where
|
||||
Self::Vox: 'a,
|
||||
{
|
||||
type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
|
||||
|
||||
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics
|
||||
/// are implemented.
|
||||
pub trait VolSize {
|
||||
const SIZE: Vec3<u32>;
|
||||
fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
pub trait IntoPosIterator: BaseVol {
|
||||
type IntoIter: Iterator<Item = Vec3<i32>>;
|
||||
|
||||
fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
/// A volume (usually rather a reference to a volume) that is convertible into
|
||||
/// an iterator.
|
||||
pub trait IntoFullVolIterator<'a>: BaseVol
|
||||
where
|
||||
Self::Vox: 'a,
|
||||
{
|
||||
type IntoIter: Iterator<Item = (Vec3<i32>, &'a Self::Vox)>;
|
||||
|
||||
fn full_vol_iter(self) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
/// For any `&'a SizedVol: IntoVolIterator` we implement `IntoFullVolIterator`.
|
||||
/// Unfortunately we can't just implement `IntoIterator` in this generic way
|
||||
/// because it's defined in another crate. That's actually the only reason why
|
||||
/// the trait `IntoFullVolIterator` exists.
|
||||
impl<'a, T: 'a + SizedVol> IntoFullVolIterator<'a> for &'a T
|
||||
where
|
||||
Self: IntoVolIterator<'a>,
|
||||
{
|
||||
type IntoIter = <Self as IntoVolIterator<'a>>::IntoIter;
|
||||
|
||||
fn full_vol_iter(self) -> Self::IntoIter {
|
||||
self.vol_iter(self.lower_bound(), self.upper_bound())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoFullPosIterator: BaseVol {
|
||||
type IntoIter: Iterator<Item = Vec3<i32>>;
|
||||
|
||||
fn full_pos_iter(self) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + SizedVol> IntoFullPosIterator for &'a T
|
||||
where
|
||||
Self: IntoPosIterator,
|
||||
{
|
||||
type IntoIter = <Self as IntoPosIterator>::IntoIter;
|
||||
|
||||
fn full_pos_iter(self) -> Self::IntoIter {
|
||||
self.pos_iter(self.lower_bound(), self.upper_bound())
|
||||
}
|
||||
}
|
||||
|
||||
// Defaults
|
||||
|
||||
/// Convenience iterator type that can be used to quickly implement
|
||||
/// `IntoPosIterator`.
|
||||
pub struct DefaultPosIterator {
|
||||
current: Vec3<i32>,
|
||||
begin: Vec2<i32>,
|
||||
end: Vec3<i32>,
|
||||
}
|
||||
|
||||
impl DefaultPosIterator {
|
||||
pub fn new(lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
|
||||
Self {
|
||||
current: lower_bound,
|
||||
begin: From::from(lower_bound),
|
||||
end: upper_bound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for DefaultPosIterator {
|
||||
type Item = Vec3<i32>;
|
||||
|
||||
fn next(&mut self) -> Option<Vec3<i32>> {
|
||||
self.current.x += (self.current.x < self.end.x) as i32;
|
||||
if self.current.x == self.end.x {
|
||||
self.current.x = self.begin.x;
|
||||
self.current.y += (self.current.y < self.end.y) as i32;
|
||||
if self.current.y == self.end.y {
|
||||
self.current.y = self.begin.y;
|
||||
self.current.z += (self.current.z < self.end.z) as i32;
|
||||
if self.current.z == self.end.z {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(self.current)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience iterator type that can be used to quickly implement
|
||||
/// `IntoVolIterator`.
|
||||
pub struct DefaultVolIterator<'a, T: ReadVol> {
|
||||
vol: &'a T,
|
||||
pos_iter: DefaultPosIterator,
|
||||
}
|
||||
|
||||
impl<'a, T: ReadVol> DefaultVolIterator<'a, T> {
|
||||
pub fn new(vol: &'a T, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self {
|
||||
Self {
|
||||
vol,
|
||||
pos_iter: DefaultPosIterator::new(lower_bound, upper_bound),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ReadVol> Iterator for DefaultVolIterator<'a, T> {
|
||||
type Item = (Vec3<i32>, &'a T::Vox);
|
||||
|
||||
fn next(&mut self) -> Option<(Vec3<i32>, &'a T::Vox)> {
|
||||
while let Some(pos) = self.pos_iter.next() {
|
||||
if let Ok(vox) = self.vol.get(pos) {
|
||||
return Some((pos, vox));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::marker::PhantomData;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChunkErr {
|
||||
pub enum ChunkError {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
@ -43,32 +43,37 @@ impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
|
||||
|
||||
impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
|
||||
type Vox = V;
|
||||
type Err = ChunkErr;
|
||||
type Error = ChunkError;
|
||||
}
|
||||
|
||||
impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> {
|
||||
S::SIZE
|
||||
fn lower_bound(&self) -> Vec3<i32> {
|
||||
Vec3::zero()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn upper_bound(&self) -> Vec3<i32> {
|
||||
S::SIZE.map(|e| e as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, ChunkErr> {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, ChunkError> {
|
||||
Self::idx_for(pos)
|
||||
.and_then(|idx| self.vox.get(idx))
|
||||
.ok_or(ChunkErr::OutOfBounds)
|
||||
.ok_or(ChunkError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, S: VolSize, M> WriteVol for Chunk<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), ChunkErr> {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), ChunkError> {
|
||||
Self::idx_for(pos)
|
||||
.and_then(|idx| self.vox.get_mut(idx))
|
||||
.map(|old_vox| *old_vox = vox)
|
||||
.ok_or(ChunkErr::OutOfBounds)
|
||||
.ok_or(ChunkError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol};
|
||||
use crate::vol::{
|
||||
BaseVol, DefaultPosIterator, DefaultVolIterator, IntoPosIterator, IntoVolIterator, ReadVol,
|
||||
SizedVol, Vox, WriteVol,
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DynaErr {
|
||||
pub enum DynaError {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
@ -40,32 +43,53 @@ impl<V: Vox, M> Dyna<V, M> {
|
||||
|
||||
impl<V: Vox, M> BaseVol for Dyna<V, M> {
|
||||
type Vox = V;
|
||||
type Err = DynaErr;
|
||||
type Error = DynaError;
|
||||
}
|
||||
|
||||
impl<V: Vox, M> SizedVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> {
|
||||
self.sz
|
||||
fn lower_bound(&self) -> Vec3<i32> {
|
||||
Vec3::zero()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn upper_bound(&self) -> Vec3<i32> {
|
||||
self.sz.map(|e| e as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, M> ReadVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaError> {
|
||||
Self::idx_for(self.sz, pos)
|
||||
.and_then(|idx| self.vox.get(idx))
|
||||
.ok_or(DynaErr::OutOfBounds)
|
||||
.ok_or(DynaError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, M> WriteVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaError> {
|
||||
Self::idx_for(self.sz, pos)
|
||||
.and_then(|idx| self.vox.get_mut(idx))
|
||||
.map(|old_vox| *old_vox = vox)
|
||||
.ok_or(DynaErr::OutOfBounds)
|
||||
.ok_or(DynaError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Vox, M> IntoPosIterator for &'a Dyna<V, M> {
|
||||
type IntoIter = DefaultPosIterator;
|
||||
|
||||
fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
|
||||
Self::IntoIter::new(lower_bound, upper_bound)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Vox, M> IntoVolIterator<'a> for &'a Dyna<V, M> {
|
||||
type IntoIter = DefaultVolIterator<'a, Dyna<V, M>>;
|
||||
|
||||
fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> Self::IntoIter {
|
||||
Self::IntoIter::new(self, lower_bound, upper_bound)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub mod chunk;
|
||||
pub mod dyna;
|
||||
pub mod vol_map_2d;
|
||||
pub mod vol_map_3d;
|
||||
pub mod vol_grid_2d;
|
||||
pub mod vol_grid_3d;
|
||||
|
@ -1,16 +1,16 @@
|
||||
use crate::{
|
||||
vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol},
|
||||
volumes::dyna::DynaErr,
|
||||
vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, WriteVol},
|
||||
volumes::dyna::DynaError,
|
||||
};
|
||||
use hashbrown::{hash_map, HashMap};
|
||||
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VolMap2dErr<V: BaseVol> {
|
||||
pub enum VolGrid2dError<V: RectRasterableVol> {
|
||||
NoSuchChunk,
|
||||
ChunkErr(V::Err),
|
||||
DynaErr(DynaErr),
|
||||
ChunkError(V::Error),
|
||||
DynaError(DynaError),
|
||||
InvalidChunkSize,
|
||||
}
|
||||
|
||||
@ -18,56 +18,55 @@ pub enum VolMap2dErr<V: BaseVol> {
|
||||
// S = Size (replace with a const when const generics is a thing)
|
||||
// M = Chunk metadata
|
||||
#[derive(Clone)]
|
||||
pub struct VolMap2d<V: BaseVol, S: VolSize> {
|
||||
pub struct VolGrid2d<V: RectRasterableVol> {
|
||||
chunks: HashMap<Vec2<i32>, Arc<V>>,
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
|
||||
impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
#[inline(always)]
|
||||
pub fn chunk_key<P: Into<Vec2<i32>>>(pos: P) -> Vec2<i32> {
|
||||
pos.into()
|
||||
.map2(S::SIZE.into(), |e, sz: u32| e >> (sz - 1).count_ones())
|
||||
.map2(V::RECT_SIZE, |e, sz: u32| e >> (sz - 1).count_ones())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> {
|
||||
let offs = pos.map2(S::SIZE, |e, sz| e & (sz - 1) as i32);
|
||||
let offs = Vec2::<i32>::from(pos).map2(V::RECT_SIZE, |e, sz| e & (sz - 1) as i32);
|
||||
Vec3::new(offs.x, offs.y, pos.z)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap2d<V, S> {
|
||||
impl<V: RectRasterableVol + Debug> BaseVol for VolGrid2d<V> {
|
||||
type Vox = V::Vox;
|
||||
type Err = VolMap2dErr<V>;
|
||||
type Error = VolGrid2dError<V>;
|
||||
}
|
||||
|
||||
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap2d<V, S> {
|
||||
impl<V: RectRasterableVol + ReadVol + Debug> ReadVol for VolGrid2d<V> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap2dErr<V>> {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolGrid2dError<V>> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks
|
||||
.get(&ck)
|
||||
.ok_or(VolMap2dErr::NoSuchChunk)
|
||||
.ok_or(VolGrid2dError::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
chunk.get(co).map_err(VolMap2dErr::ChunkErr)
|
||||
chunk.get(co).map_err(VolGrid2dError::ChunkError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This actually breaks the API: samples are supposed to have an offset of zero!
|
||||
// TODO: Should this be changed, perhaps?
|
||||
impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap2d<V, S> {
|
||||
type Sample = VolMap2d<V, S>;
|
||||
impl<I: Into<Aabr<i32>>, V: RectRasterableVol + ReadVol + Debug> SampleVol<I> for VolGrid2d<V> {
|
||||
type Sample = VolGrid2d<V>;
|
||||
|
||||
/// Take a sample of the terrain by cloning the voxels within the provided range.
|
||||
///
|
||||
/// Note that the resultant volume does not carry forward metadata from the original chunks.
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, VolMap2dErr<V>> {
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, VolGrid2dError<V>> {
|
||||
let range = range.into();
|
||||
|
||||
let mut sample = VolMap2d::new()?;
|
||||
let mut sample = VolGrid2d::new()?;
|
||||
let chunk_min = Self::chunk_key(range.min);
|
||||
let chunk_max = Self::chunk_key(range.max);
|
||||
for x in chunk_min.x..=chunk_max.x {
|
||||
@ -86,39 +85,38 @@ impl<I: Into<Aabr<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I>
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap2d<V, S> {
|
||||
impl<V: RectRasterableVol + WriteVol + Clone + Debug> WriteVol for VolGrid2d<V> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap2dErr<V>> {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolGrid2dError<V>> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks
|
||||
.get_mut(&ck)
|
||||
.ok_or(VolMap2dErr::NoSuchChunk)
|
||||
.ok_or(VolGrid2dError::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
Arc::make_mut(chunk)
|
||||
.set(co, vox)
|
||||
.map_err(VolMap2dErr::ChunkErr)
|
||||
.map_err(VolGrid2dError::ChunkError)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
|
||||
pub fn new() -> Result<Self, VolMap2dErr<V>> {
|
||||
impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
pub fn new() -> Result<Self, VolGrid2dError<V>> {
|
||||
if Self::chunk_size()
|
||||
.map(|e| e.is_power_of_two() && e > 0)
|
||||
.reduce_and()
|
||||
{
|
||||
Ok(Self {
|
||||
chunks: HashMap::default(),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(VolMap2dErr::InvalidChunkSize)
|
||||
Err(VolGrid2dError::InvalidChunkSize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chunk_size() -> Vec2<u32> {
|
||||
S::SIZE.into()
|
||||
V::RECT_SIZE
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: Vec2<i32>, chunk: Arc<V>) -> Option<Arc<V>> {
|
||||
@ -149,7 +147,7 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
|
||||
}
|
||||
|
||||
pub fn key_pos(&self, key: Vec2<i32>) -> Vec2<i32> {
|
||||
key * Vec2::<u32>::from(S::SIZE).map(|e| e as i32)
|
||||
key * V::RECT_SIZE.map(|e| e as i32)
|
||||
}
|
||||
|
||||
pub fn pos_key(&self, pos: Vec3<i32>) -> Vec2<i32> {
|
||||
@ -163,11 +161,11 @@ impl<V: BaseVol, S: VolSize> VolMap2d<V, S> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChunkIter<'a, V: BaseVol> {
|
||||
pub struct ChunkIter<'a, V: RectRasterableVol> {
|
||||
iter: hash_map::Iter<'a, Vec2<i32>, Arc<V>>,
|
||||
}
|
||||
|
||||
impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> {
|
||||
impl<'a, V: RectRasterableVol> Iterator for ChunkIter<'a, V> {
|
||||
type Item = (Vec2<i32>, &'a Arc<V>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
@ -1,16 +1,16 @@
|
||||
use crate::{
|
||||
vol::{BaseVol, ReadVol, SampleVol, VolSize, WriteVol},
|
||||
volumes::dyna::DynaErr,
|
||||
vol::{BaseVol, RasterableVol, ReadVol, SampleVol, WriteVol},
|
||||
volumes::dyna::DynaError,
|
||||
};
|
||||
use hashbrown::{hash_map, HashMap};
|
||||
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VolMap3dErr<V: BaseVol> {
|
||||
pub enum VolGrid3dError<V: RasterableVol> {
|
||||
NoSuchChunk,
|
||||
ChunkErr(V::Err),
|
||||
DynaErr(DynaErr),
|
||||
ChunkErr(V::Error),
|
||||
DynaError(DynaError),
|
||||
InvalidChunkSize,
|
||||
}
|
||||
|
||||
@ -18,15 +18,14 @@ pub enum VolMap3dErr<V: BaseVol> {
|
||||
// S = Size (replace with a const when const generics is a thing)
|
||||
// M = Chunk metadata
|
||||
#[derive(Clone)]
|
||||
pub struct VolMap3d<V: BaseVol, S: VolSize> {
|
||||
pub struct VolGrid3d<V: RasterableVol> {
|
||||
chunks: HashMap<Vec3<i32>, Arc<V>>,
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
|
||||
impl<V: RasterableVol> VolGrid3d<V> {
|
||||
#[inline(always)]
|
||||
pub fn chunk_key(pos: Vec3<i32>) -> Vec3<i32> {
|
||||
pos.map2(S::SIZE, |e, sz| {
|
||||
pos.map2(V::SIZE, |e, sz| {
|
||||
// Horrid, but it's faster than a cheetah with a red bull blood transfusion
|
||||
let log2 = (sz - 1).count_ones();
|
||||
((((i64::from(e) + (1 << 32)) as u64) >> log2) - (1 << (32 - log2))) as i32
|
||||
@ -35,43 +34,43 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn chunk_offs(pos: Vec3<i32>) -> Vec3<i32> {
|
||||
pos.map2(S::SIZE, |e, sz| {
|
||||
pos.map2(V::SIZE, |e, sz| {
|
||||
// Horrid, but it's even faster than the aforementioned cheetah
|
||||
(((i64::from(e) + (1 << 32)) as u64) & u64::from(sz - 1)) as i32
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol + Debug, S: VolSize> BaseVol for VolMap3d<V, S> {
|
||||
impl<V: RasterableVol + Debug> BaseVol for VolGrid3d<V> {
|
||||
type Vox = V::Vox;
|
||||
type Err = VolMap3dErr<V>;
|
||||
type Error = VolGrid3dError<V>;
|
||||
}
|
||||
|
||||
impl<V: BaseVol + ReadVol + Debug, S: VolSize> ReadVol for VolMap3d<V, S> {
|
||||
impl<V: RasterableVol + ReadVol + Debug> ReadVol for VolGrid3d<V> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolMap3dErr<V>> {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V::Vox, VolGrid3dError<V>> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks
|
||||
.get(&ck)
|
||||
.ok_or(VolMap3dErr::NoSuchChunk)
|
||||
.ok_or(VolGrid3dError::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
chunk.get(co).map_err(VolMap3dErr::ChunkErr)
|
||||
chunk.get(co).map_err(VolGrid3dError::ChunkErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This actually breaks the API: samples are supposed to have an offset of zero!
|
||||
// TODO: Should this be changed, perhaps?
|
||||
impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I> for VolMap3d<V, S> {
|
||||
type Sample = VolMap3d<V, S>;
|
||||
impl<I: Into<Aabb<i32>>, V: RasterableVol + ReadVol + Debug> SampleVol<I> for VolGrid3d<V> {
|
||||
type Sample = VolGrid3d<V>;
|
||||
|
||||
/// Take a sample of the terrain by cloning the voxels within the provided range.
|
||||
///
|
||||
/// Note that the resultant volume does not carry forward metadata from the original chunks.
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, VolMap3dErr<V>> {
|
||||
fn sample(&self, range: I) -> Result<Self::Sample, VolGrid3dError<V>> {
|
||||
let range = range.into();
|
||||
let mut sample = VolMap3d::new()?;
|
||||
let mut sample = VolGrid3d::new()?;
|
||||
let chunk_min = Self::chunk_key(range.min);
|
||||
let chunk_max = Self::chunk_key(range.max);
|
||||
for x in chunk_min.x..=chunk_max.x {
|
||||
@ -92,39 +91,38 @@ impl<I: Into<Aabb<i32>>, V: BaseVol + ReadVol + Debug, S: VolSize> SampleVol<I>
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol + WriteVol + Clone + Debug, S: VolSize + Clone> WriteVol for VolMap3d<V, S> {
|
||||
impl<V: RasterableVol + WriteVol + Clone + Debug> WriteVol for VolGrid3d<V> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolMap3dErr<V>> {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V::Vox) -> Result<(), VolGrid3dError<V>> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks
|
||||
.get_mut(&ck)
|
||||
.ok_or(VolMap3dErr::NoSuchChunk)
|
||||
.ok_or(VolGrid3dError::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
Arc::make_mut(chunk)
|
||||
.set(co, vox)
|
||||
.map_err(VolMap3dErr::ChunkErr)
|
||||
.map_err(VolGrid3dError::ChunkErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
|
||||
pub fn new() -> Result<Self, VolMap3dErr<V>> {
|
||||
impl<V: RasterableVol> VolGrid3d<V> {
|
||||
pub fn new() -> Result<Self, VolGrid3dError<V>> {
|
||||
if Self::chunk_size()
|
||||
.map(|e| e.is_power_of_two() && e > 0)
|
||||
.reduce_and()
|
||||
{
|
||||
Ok(Self {
|
||||
chunks: HashMap::new(),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(VolMap3dErr::InvalidChunkSize)
|
||||
Err(VolGrid3dError::InvalidChunkSize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chunk_size() -> Vec3<u32> {
|
||||
S::SIZE
|
||||
V::SIZE
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: Vec3<i32>, chunk: Arc<V>) -> Option<Arc<V>> {
|
||||
@ -147,7 +145,7 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
|
||||
}
|
||||
|
||||
pub fn key_pos(&self, key: Vec3<i32>) -> Vec3<i32> {
|
||||
key * S::SIZE.map(|e| e as i32)
|
||||
key * V::SIZE.map(|e| e as i32)
|
||||
}
|
||||
|
||||
pub fn pos_key(&self, pos: Vec3<i32>) -> Vec3<i32> {
|
||||
@ -161,11 +159,11 @@ impl<V: BaseVol, S: VolSize> VolMap3d<V, S> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChunkIter<'a, V: BaseVol> {
|
||||
pub struct ChunkIter<'a, V: RasterableVol> {
|
||||
iter: hash_map::Iter<'a, Vec3<i32>, Arc<V>>,
|
||||
}
|
||||
|
||||
impl<'a, V: BaseVol> Iterator for ChunkIter<'a, V> {
|
||||
impl<'a, V: RasterableVol> Iterator for ChunkIter<'a, V> {
|
||||
type Item = (Vec3<i32>, &'a Arc<V>);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
@ -0,0 +1 @@
|
||||
|
@ -846,7 +846,7 @@ fn handle_debug_column(server: &mut Server, entity: EcsEntity, args: String, act
|
||||
let sim = server.world.sim();
|
||||
if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) {
|
||||
let wpos = Vec2::new(x, y);
|
||||
/* let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
/* let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
||||
e / sz as i32
|
||||
}); */
|
||||
|
||||
|
@ -22,9 +22,8 @@ use common::{
|
||||
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
|
||||
net::PostOffice,
|
||||
state::{BlockChange, State, TimeOfDay, Uid},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
|
||||
vol::Vox,
|
||||
vol::{ReadVol, VolSize},
|
||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainGrid},
|
||||
vol::{ReadVol, RectVolSize, Vox},
|
||||
};
|
||||
use crossbeam::channel;
|
||||
use hashbrown::HashSet;
|
||||
@ -261,7 +260,7 @@ impl Server {
|
||||
let mut block_change = ecs.write_resource::<BlockChange>();
|
||||
|
||||
let _ = ecs
|
||||
.read_resource::<TerrainMap>()
|
||||
.read_resource::<TerrainGrid>()
|
||||
.ray(pos, pos + dir * radius)
|
||||
.until(|_| rand::random::<f32>() < 0.05)
|
||||
.for_each(|pos| block_change.set(pos, Block::empty()))
|
||||
@ -479,7 +478,7 @@ impl Server {
|
||||
fn chunk_in_vd(
|
||||
player_pos: Vec3<f32>,
|
||||
chunk_pos: Vec2<i32>,
|
||||
terrain: &TerrainMap,
|
||||
terrain: &TerrainGrid,
|
||||
vd: u32,
|
||||
) -> bool {
|
||||
let player_chunk_pos = terrain.pos_key(player_pos.map(|e| e as i32));
|
||||
@ -1085,8 +1084,8 @@ impl Server {
|
||||
) {
|
||||
{
|
||||
// Check if the entity is in the client's range
|
||||
(pos.0 - client_pos.0)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| {
|
||||
Vec2::from(pos.0 - client_pos.0)
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |d: f32, sz| {
|
||||
(d.abs() as u32 / sz).checked_sub(2).unwrap_or(0)
|
||||
})
|
||||
.magnitude_squared()
|
||||
|
@ -40,7 +40,6 @@ impl Animation for WieldAnimation {
|
||||
* 0.1,
|
||||
);
|
||||
|
||||
|
||||
match Tool::Hammer {
|
||||
//TODO: Inventory
|
||||
Tool::Sword => {
|
||||
|
@ -39,7 +39,7 @@ use crate::{
|
||||
GlobalState,
|
||||
};
|
||||
use client::{Client, Event as ClientEvent};
|
||||
use common::{comp, terrain::TerrainChunkSize, vol::VolSize};
|
||||
use common::{comp, terrain::TerrainChunk, vol::RectRasterableVol};
|
||||
use conrod_core::{
|
||||
text::cursor::Index,
|
||||
widget::{self, Button, Image, Rectangle, Text},
|
||||
@ -482,8 +482,10 @@ impl Hud {
|
||||
.filter(|(entity, _, stats, _, _)| *entity != me && !stats.is_dead)
|
||||
// Don't process nametags outside the vd (visibility further limited by ui backend)
|
||||
.filter(|(_, pos, _, _, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
Vec2::from(pos.0 - player_pos)
|
||||
.map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
|
||||
d.abs() as f32 / sz as f32
|
||||
})
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
@ -523,8 +525,10 @@ impl Hud {
|
||||
})
|
||||
// Don't process health bars outside the vd (visibility further limited by ui backend)
|
||||
.filter(|(_, pos, _, _)| {
|
||||
(pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
Vec2::from(pos.0 - player_pos)
|
||||
.map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
|
||||
d.abs() as f32 / sz as f32
|
||||
})
|
||||
.magnitude()
|
||||
< view_distance as f32
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
use common::{
|
||||
figure::Segment,
|
||||
util::{linear_to_srgb, srgb_to_linear},
|
||||
vol::{ReadVol, SizedVol, Vox},
|
||||
vol::{IntoFullVolIterator, Vox},
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
@ -23,8 +23,8 @@ impl Meshable<FigurePipeline, FigurePipeline> for Segment {
|
||||
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
for pos in self.iter_positions() {
|
||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
||||
for (pos, vox) in self.full_vol_iter() {
|
||||
if let Some(col) = vox.get_color() {
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
vol::push_vox_verts(
|
||||
@ -64,8 +64,8 @@ impl Meshable<SpritePipeline, SpritePipeline> for Segment {
|
||||
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
for pos in self.iter_positions() {
|
||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
||||
for (pos, vox) in self.full_vol_iter() {
|
||||
if let Some(col) = vox.get_color() {
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
vol::push_vox_verts(
|
||||
|
@ -4,8 +4,8 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
terrain::{Block, BlockKind},
|
||||
vol::{BaseVol, ReadVol, VolSize},
|
||||
volumes::vol_map_2d::VolMap2d,
|
||||
vol::{ReadVol, RectRasterableVol},
|
||||
volumes::vol_grid_2d::VolGrid2d,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
use vek::*;
|
||||
@ -24,8 +24,8 @@ fn block_shadow_density(kind: BlockKind) -> (f32, f32) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone>
|
||||
Meshable<TerrainPipeline, FluidPipeline> for VolMap2d<V, S>
|
||||
impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeline, FluidPipeline>
|
||||
for VolGrid2d<V>
|
||||
{
|
||||
type Pipeline = TerrainPipeline;
|
||||
type TranslucentPipeline = FluidPipeline;
|
||||
@ -126,7 +126,7 @@ impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone>
|
||||
}
|
||||
|
||||
/*
|
||||
impl<V: BaseVol<Vox = Block> + ReadVol + Debug, S: VolSize + Clone> Meshable for VolMap3d<V, S> {
|
||||
impl<V: BaseVol<Vox = Block> + ReadVol + Debug> Meshable for VolGrid3d<V> {
|
||||
type Pipeline = TerrainPipeline;
|
||||
type Supplement = Aabb<i32>;
|
||||
|
||||
|
@ -17,8 +17,8 @@ use common::{
|
||||
comp::{
|
||||
ActionState::*, Body, CharacterState, Last, MovementState::*, Ori, Pos, Scale, Stats, Vel,
|
||||
},
|
||||
terrain::TerrainChunkSize,
|
||||
vol::VolSize,
|
||||
terrain::TerrainChunk,
|
||||
vol::RectRasterableVol,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use log::debug;
|
||||
@ -77,8 +77,10 @@ impl FigureMgr {
|
||||
.join()
|
||||
{
|
||||
// Don't process figures outside the vd
|
||||
let vd_frac = (pos.0 - player_pos)
|
||||
.map2(TerrainChunkSize::SIZE, |d, sz| d.abs() as f32 / sz as f32)
|
||||
let vd_frac = Vec2::from(pos.0 - player_pos)
|
||||
.map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
|
||||
d.abs() as f32 / sz as f32
|
||||
})
|
||||
.magnitude()
|
||||
/ view_distance as f32;
|
||||
// Keep from re-adding/removing entities on the border of the vd
|
||||
|
@ -10,9 +10,9 @@ use client::Client;
|
||||
use common::{
|
||||
assets,
|
||||
figure::Segment,
|
||||
terrain::{Block, BlockKind, TerrainChunkSize, TerrainMap},
|
||||
vol::{ReadVol, SampleVol, VolSize, Vox},
|
||||
volumes::vol_map_2d::VolMap2dErr,
|
||||
terrain::{Block, BlockKind, TerrainChunkSize, TerrainGrid},
|
||||
vol::{ReadVol, RectVolSize, SampleVol, Vox},
|
||||
volumes::vol_grid_2d::VolGrid2dError,
|
||||
};
|
||||
use crossbeam::channel;
|
||||
use dot_vox::DotVoxData;
|
||||
@ -139,7 +139,7 @@ fn mesh_worker(
|
||||
pos: Vec2<i32>,
|
||||
z_bounds: (f32, f32),
|
||||
started_tick: u64,
|
||||
volume: <TerrainMap as SampleVol<Aabr<i32>>>::Sample,
|
||||
volume: <TerrainGrid as SampleVol<Aabr<i32>>>::Sample,
|
||||
range: Aabb<i32>,
|
||||
) -> MeshWorkerResponse {
|
||||
let (opaque_mesh, fluid_mesh) = volume.generate_mesh(range);
|
||||
@ -152,11 +152,11 @@ fn mesh_worker(
|
||||
sprite_instances: {
|
||||
let mut instances = HashMap::new();
|
||||
|
||||
for x in 0..TerrainChunkSize::SIZE.x as i32 {
|
||||
for y in 0..TerrainChunkSize::SIZE.y as i32 {
|
||||
for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 {
|
||||
for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 {
|
||||
for z in z_bounds.0 as i32..z_bounds.1 as i32 + 1 {
|
||||
let wpos = Vec3::from(
|
||||
pos * Vec2::from(TerrainChunkSize::SIZE).map(|e: u32| e as i32),
|
||||
pos * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32),
|
||||
) + Vec3::new(x, y, z);
|
||||
|
||||
let kind = volume.get(wpos).unwrap_or(&Block::empty()).kind();
|
||||
@ -728,10 +728,10 @@ impl Terrain {
|
||||
let aabr = Aabr {
|
||||
min: todo
|
||||
.pos
|
||||
.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1),
|
||||
.map2(TerrainGrid::chunk_size(), |e, sz| e * sz as i32 - 1),
|
||||
max: todo
|
||||
.pos
|
||||
.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
||||
.map2(TerrainGrid::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
||||
};
|
||||
|
||||
// Copy out the chunk data we need to perform the meshing. We do this by taking a
|
||||
@ -740,7 +740,7 @@ impl Terrain {
|
||||
Ok(sample) => sample,
|
||||
// Either this chunk or its neighbours doesn't yet exist, so we keep it in the
|
||||
// queue to be processed at a later date when we have its neighbours.
|
||||
Err(VolMap2dErr::NoSuchChunk) => return,
|
||||
Err(VolGrid2dError::NoSuchChunk) => return,
|
||||
_ => panic!("Unhandled edge case"),
|
||||
};
|
||||
|
||||
@ -807,7 +807,7 @@ impl Terrain {
|
||||
locals: renderer
|
||||
.create_consts(&[TerrainLocals {
|
||||
model_offs: Vec3::from(
|
||||
response.pos.map2(TerrainMap::chunk_size(), |e, sz| {
|
||||
response.pos.map2(TerrainGrid::chunk_size(), |e, sz| {
|
||||
e as f32 * sz as f32
|
||||
}),
|
||||
)
|
||||
@ -836,7 +836,7 @@ impl Terrain {
|
||||
);
|
||||
|
||||
// Update chunk visibility
|
||||
let chunk_sz = TerrainChunkSize::SIZE.x as f32;
|
||||
let chunk_sz = TerrainChunkSize::RECT_SIZE.x as f32;
|
||||
for (pos, chunk) in &mut self.chunks {
|
||||
let chunk_pos = pos.map(|e| e as f32 * chunk_sz);
|
||||
|
||||
@ -886,9 +886,10 @@ impl Terrain {
|
||||
if chunk.visible {
|
||||
const SPRITE_RENDER_DISTANCE: f32 = 128.0;
|
||||
|
||||
let chunk_center = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
(e as f32 + 0.5) * sz as f32
|
||||
});
|
||||
let chunk_center = pos
|
||||
.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| {
|
||||
(e as f32 + 0.5) * sz as f32
|
||||
});
|
||||
if Vec2::from(focus_pos).distance_squared(chunk_center)
|
||||
< SPRITE_RENDER_DISTANCE * SPRITE_RENDER_DISTANCE
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
use common::{
|
||||
figure::Segment,
|
||||
util::{linear_to_srgba, srgba_to_linear},
|
||||
vol::{ReadVol, SizedVol, Vox},
|
||||
vol::{IntoFullVolIterator, ReadVol, SizedVol, Vox},
|
||||
};
|
||||
use euc::{buffer::Buffer2d, rasterizer, Pipeline};
|
||||
use image::{DynamicImage, RgbaImage};
|
||||
@ -69,7 +69,7 @@ pub fn draw_vox(
|
||||
let mut color = Buffer2d::new(dims, [0; 4]);
|
||||
let mut depth = Buffer2d::new(dims, 1.0);
|
||||
|
||||
let (w, h, d) = segment.get_size().map(|e| e as f32).into_tuple();
|
||||
let (w, h, d) = segment.size().map(|e| e as f32).into_tuple();
|
||||
|
||||
let mvp = Mat4::<f32>::orthographic_rh_no(FrustumPlanes {
|
||||
left: -1.0,
|
||||
@ -155,8 +155,8 @@ fn create_quad(
|
||||
fn generate_mesh(segment: &Segment, offs: Vec3<f32>) -> Vec<Vert> {
|
||||
let mut vertices = Vec::new();
|
||||
|
||||
for pos in segment.iter_positions() {
|
||||
if let Some(col) = segment.get(pos).ok().and_then(|vox| vox.get_color()) {
|
||||
for (pos, vox) in segment.full_vol_iter() {
|
||||
if let Some(col) = vox.get_color() {
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
let is_empty = |pos| segment.get(pos).map(|v| v.is_empty()).unwrap_or(true);
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
use common::{
|
||||
assets,
|
||||
terrain::{BlockKind, Structure, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
use noise::NoiseFn;
|
||||
@ -71,9 +71,7 @@ impl<'a> ColumnGen<'a> {
|
||||
.min_by_key(|(pos, _)| pos.distance_squared(wpos))
|
||||
.unwrap();
|
||||
|
||||
let chunk_pos = pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
e / sz as i32
|
||||
});
|
||||
let chunk_pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
||||
let chunk = self.sim.get(chunk_pos)?;
|
||||
|
||||
if seed % 5 == 2
|
||||
@ -126,9 +124,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
||||
|
||||
fn get(&self, wpos: Vec2<i32>) -> Option<ColumnSample<'a>> {
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
e / sz as i32
|
||||
});
|
||||
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
||||
|
||||
let sim = &self.sim;
|
||||
|
||||
|
@ -34,13 +34,13 @@ impl TownColumn {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Module {
|
||||
pub vol_idx: usize,
|
||||
pub dir: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CellKind {
|
||||
Empty,
|
||||
Park,
|
||||
@ -50,7 +50,7 @@ pub enum CellKind {
|
||||
House(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct TownCell {
|
||||
pub kind: CellKind,
|
||||
pub module: Option<Module>,
|
||||
@ -200,11 +200,11 @@ impl TownVol {
|
||||
|
||||
impl BaseVol for TownVol {
|
||||
type Vox = TownCell;
|
||||
type Err = TownError;
|
||||
type Error = TownError;
|
||||
}
|
||||
|
||||
impl ReadVol for TownVol {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err> {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
|
||||
match self.grid.get(Vec2::from(pos)) {
|
||||
Some((base, _, cells)) => cells
|
||||
.get((pos.z + UNDERGROUND_DEPTH - *base) as usize)
|
||||
@ -215,7 +215,7 @@ impl ReadVol for TownVol {
|
||||
}
|
||||
|
||||
impl WriteVol for TownVol {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err> {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error> {
|
||||
match self.grid.get_mut(Vec2::from(pos)) {
|
||||
Some((base, _, cells)) => cells
|
||||
.get_mut((pos.z + UNDERGROUND_DEPTH - *base) as usize)
|
||||
|
@ -25,7 +25,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
terrain::{Block, BlockKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
vol::{ReadVol, VolSize, Vox, WriteVol},
|
||||
vol::{ReadVol, RectVolSize, Vox, WriteVol},
|
||||
};
|
||||
use rand::Rng;
|
||||
use std::time::Duration;
|
||||
@ -70,7 +70,7 @@ impl World {
|
||||
let stone = Block::new(BlockKind::Dense, Rgb::new(200, 220, 255));
|
||||
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
|
||||
|
||||
let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE);
|
||||
let chunk_size2d = TerrainChunkSize::RECT_SIZE;
|
||||
let (base_z, sim_chunk) = match self
|
||||
.sim
|
||||
.get_interpolated(
|
||||
@ -96,13 +96,13 @@ impl World {
|
||||
let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome());
|
||||
let mut sampler = self.sample_blocks();
|
||||
|
||||
let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32);
|
||||
let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
|
||||
|
||||
let mut chunk = TerrainChunk::new(base_z, stone, air, meta);
|
||||
for x in 0..TerrainChunkSize::SIZE.x as i32 {
|
||||
for y in 0..TerrainChunkSize::SIZE.y as i32 {
|
||||
for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 {
|
||||
for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 {
|
||||
let wpos2d = Vec2::new(x, y)
|
||||
+ Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32);
|
||||
+ Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
|
||||
|
||||
let z_cache = match sampler.get_z_cache(wpos2d) {
|
||||
Some(z_cache) => z_cache,
|
||||
@ -127,7 +127,7 @@ impl World {
|
||||
}
|
||||
|
||||
let gen_entity_pos = || {
|
||||
let lpos2d = Vec2::from(TerrainChunkSize::SIZE)
|
||||
let lpos2d = TerrainChunkSize::RECT_SIZE
|
||||
.map(|sz| rand::thread_rng().gen::<u32>().rem_euclid(sz));
|
||||
let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0);
|
||||
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
terrain::{BiomeKind, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use noise::{
|
||||
BasicMulti, Billow, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex,
|
||||
@ -328,7 +328,7 @@ impl WorldSim {
|
||||
self.rng.gen::<usize>() % grid_size.y,
|
||||
);
|
||||
let wpos = (cell_pos * cell_size + cell_size / 2)
|
||||
.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
||||
e as i32 * sz as i32 + sz as i32 / 2
|
||||
});
|
||||
|
||||
@ -378,8 +378,8 @@ impl WorldSim {
|
||||
for j in 0..WORLD_SIZE.y {
|
||||
let chunk_pos = Vec2::new(i as i32, j as i32);
|
||||
let block_pos = Vec2::new(
|
||||
chunk_pos.x * TerrainChunkSize::SIZE.x as i32,
|
||||
chunk_pos.y * TerrainChunkSize::SIZE.y as i32,
|
||||
chunk_pos.x * TerrainChunkSize::RECT_SIZE.x as i32,
|
||||
chunk_pos.y * TerrainChunkSize::RECT_SIZE.y as i32,
|
||||
);
|
||||
let _cell_pos = Vec2::new(i / cell_size, j / cell_size);
|
||||
|
||||
@ -389,9 +389,8 @@ impl WorldSim {
|
||||
.iter()
|
||||
.map(|(pos, seed)| RegionInfo {
|
||||
chunk_pos: *pos,
|
||||
block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
e * sz as i32
|
||||
}),
|
||||
block_pos: pos
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e * sz as i32),
|
||||
dist: (pos - chunk_pos).map(|e| e as f32).magnitude(),
|
||||
seed: *seed,
|
||||
})
|
||||
@ -429,7 +428,7 @@ impl WorldSim {
|
||||
for i in 0..WORLD_SIZE.x {
|
||||
for j in 0..WORLD_SIZE.y {
|
||||
let chunk_pos = Vec2::new(i as i32, j as i32);
|
||||
let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
let wpos = chunk_pos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| {
|
||||
e * sz as i32 + sz as i32 / 2
|
||||
});
|
||||
|
||||
@ -474,9 +473,11 @@ impl WorldSim {
|
||||
}
|
||||
|
||||
pub fn get_wpos(&self, wpos: Vec2<i32>) -> Option<&SimChunk> {
|
||||
self.get(wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
e / sz as i32
|
||||
}))
|
||||
self.get(
|
||||
wpos.map2(Vec2::from(TerrainChunkSize::RECT_SIZE), |e, sz: u32| {
|
||||
e / sz as i32
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, chunk_pos: Vec2<i32>) -> Option<&mut SimChunk> {
|
||||
@ -509,7 +510,7 @@ impl WorldSim {
|
||||
T: Copy + Default + Add<Output = T> + Mul<f32, Output = T>,
|
||||
F: FnMut(&SimChunk) -> T,
|
||||
{
|
||||
let pos = pos.map2(TerrainChunkSize::SIZE.into(), |e, sz: u32| {
|
||||
let pos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
||||
e as f64 / sz as f64
|
||||
});
|
||||
|
||||
@ -579,7 +580,7 @@ pub struct Structures {
|
||||
impl SimChunk {
|
||||
fn generate(posi: usize, gen_ctx: &mut GenCtx, gen_cdf: &GenCdf) -> Self {
|
||||
let pos = uniform_idx_as_vec2(posi);
|
||||
let wposf = (pos * TerrainChunkSize::SIZE.map(|e| e as i32)).map(|e| e as f64);
|
||||
let wposf = (pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32)).map(|e| e as f64);
|
||||
|
||||
let (_, alt_base) = gen_cdf.alt_base[posi];
|
||||
let map_edge_factor = map_edge_factor(posi);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::WORLD_SIZE;
|
||||
use common::{terrain::TerrainChunkSize, vol::VolSize};
|
||||
use common::{terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use vek::*;
|
||||
|
||||
/// Computes the cumulative distribution function of the weighted sum of k independent,
|
||||
@ -141,7 +141,7 @@ pub fn uniform_noise(f: impl Fn(usize, Vec2<f64>) -> Option<f32>) -> InverseCdf
|
||||
.filter_map(|i| {
|
||||
(f(
|
||||
i,
|
||||
(uniform_idx_as_vec2(i) * TerrainChunkSize::SIZE.map(|e| e as i32))
|
||||
(uniform_idx_as_vec2(i) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32))
|
||||
.map(|e| e as f64),
|
||||
)
|
||||
.map(|res| (i, res)))
|
||||
|
Loading…
Reference in New Issue
Block a user