1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! 2D/3D Tile data structures and functionality.
//!

#![deny(clippy::all, clippy::pedantic, missing_docs)]
#![allow(dead_code, clippy::module_name_repetitions)]

mod map;
mod morton;
mod pass;

pub mod error;
pub mod iters;
pub mod pod;
pub mod prefab;

pub use error::TileOutOfBoundsError;
pub use iters::{MortonRegion, Region};
pub use map::{Map, MapStorage, Tile, TileMap};
pub use morton::{MortonEncoder, MortonEncoder2D};
pub use pass::{
    DrawTiles2D, DrawTiles2DBounds, DrawTiles2DBoundsDefault, DrawTiles2DDesc, RenderTiles2D,
};

use amethyst_core::math::Vector3;

/// Trait to provide generic access to various encoding schemas. All tile storages use this to encode their coordinates
/// and provide different spatial encoding algorithms for efficiency.
pub trait CoordinateEncoder: 'static + Clone + Default + Send + Sync {
    /// Constructor interface for `Self` which consumes the maps dimensions, which is required for some
    /// encoding types to fit within a given coordinate space.
    fn from_dimensions(dimensions: Vector3<u32>) -> Self;

    /// Encode the provided x, y and z 3-dimensional coordinates into a 1-dimensional array index.
    fn encode(&self, x: u32, y: u32, z: u32) -> Option<u32>;

    /// Decode the provided 1-dimensional array index into its associated 3-dimensional coordinates.
    fn decode(&self, morton: u32) -> Option<(u32, u32, u32)>;

    /// This function returns the actual number of elements allocated for a given dimension set and encoder.
    fn allocation_size(dimensions: Vector3<u32>) -> usize;
}

/// The most basic encoder, which strictly flattens the 3d space into 1d coordinates in a linear fashion.
/// This encoder is optimal for storage space, but not for traversal or iteration.
#[derive(Clone)]
pub struct FlatEncoder {
    dimensions: Vector3<u32>,
}
impl Default for FlatEncoder {
    #[must_use]
    fn default() -> Self {
        Self {
            dimensions: Vector3::new(0, 0, 0),
        }
    }
}
impl CoordinateEncoder for FlatEncoder {
    #[must_use]
    fn from_dimensions(dimensions: Vector3<u32>) -> Self {
        Self { dimensions }
    }

    #[inline]
    #[must_use]
    fn encode(&self, x: u32, y: u32, z: u32) -> Option<u32> {
        Some((z * self.dimensions.x * self.dimensions.y) + (y * self.dimensions.x) + x)
    }

    #[inline]
    #[must_use]
    fn decode(&self, idx: u32) -> Option<(u32, u32, u32)> {
        let z = idx / (self.dimensions.x * self.dimensions.y);
        let idx = idx - (z * self.dimensions.x * self.dimensions.y);
        let y = idx / self.dimensions.x;
        let x = idx % self.dimensions.x;

        Some((x, y, z))
    }

    #[must_use]
    fn allocation_size(dimensions: Vector3<u32>) -> usize {
        (dimensions.x * dimensions.y * dimensions.z) as usize
    }
}