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
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::block::{BlockState, GlobalBlocks};
use crate::util::OpaquePtr;

use std::collections::HashMap;


/// A structure used to statically define an heightmap type.
///
/// The heightmap's predicate must not return true upon "null block", this restriction is needed
/// at the current state of the crate because the "null block" is currently used to optimize
/// storage.
pub struct HeightmapType {
    pub name: &'static str,
    pub predicate: fn(&'static BlockState, &GlobalBlocks) -> bool
}

impl HeightmapType {

    #[inline]
    pub fn get_name(&self) -> &'static str {
        self.name
    }

    #[inline]
    pub fn get_key(&'static self) -> HeightmapTypeKey {
        OpaquePtr::new(self)
    }

    #[inline]
    pub fn check_block(&self, state: &'static BlockState, blocks: &GlobalBlocks) -> bool {
        (self.predicate)(state, blocks)
    }

}

pub type HeightmapTypeKey = OpaquePtr<HeightmapType>;

impl PartialEq for &'static HeightmapType {
    fn eq(&self, other: &Self) -> bool {
        std::ptr::eq(*self, *other)
    }
}

impl Eq for &'static HeightmapType { }


/// A global heightmaps palette used by level, each chunk created into it will include all
/// these heightmaps and automatically computed and updated when modifying the chunk.
pub struct GlobalHeightmaps {
    heightmap_types: Vec<&'static HeightmapType>,
    heightmap_types_to_index: HashMap<HeightmapTypeKey, usize>,
}

impl GlobalHeightmaps {

    pub fn new() -> Self {
        Self {
            heightmap_types: Vec::new(),
            heightmap_types_to_index: HashMap::new()
        }
    }

    pub fn with_all(slice: &[&'static HeightmapType]) -> Self {
        let mut heightmaps = Self::new();
        heightmaps.register_all(slice);
        heightmaps
    }

    pub fn register(&mut self, heightmap_type: &'static HeightmapType) {
        self.heightmap_types_to_index.insert(heightmap_type.get_key(), self.heightmap_types.len());
        self.heightmap_types.push(heightmap_type);
    }

    pub fn register_all(&mut self, slice: &[&'static HeightmapType]) {
        self.heightmap_types.reserve(slice.len());
        self.heightmap_types_to_index.reserve(slice.len());
        for &heightmap_type in slice {
            self.register(heightmap_type);
        }
    }

    pub fn get_heightmap_index(&self, heightmap_type: &'static HeightmapType) -> Option<usize> {
        self.heightmap_types_to_index.get(&heightmap_type.get_key()).copied()
    }

    pub fn get_heightmap_from(&self, index: usize) -> Option<&'static HeightmapType> {
        self.heightmap_types.get(index).copied()
    }

    pub fn has_heightmap_type(&self, heightmap_type: &'static HeightmapType) -> bool {
        self.heightmap_types.iter().any(move |&t| t == heightmap_type)
    }

    pub fn iter_heightmap_types(&self) -> impl Iterator<Item = &'static HeightmapType> + '_ {
        self.heightmap_types.iter().copied()
    }

    pub fn heightmaps_count(&self) -> usize {
        self.heightmap_types.len()
    }

}


#[macro_export]
macro_rules! heightmaps {
    ($global_vis:vis $static_id:ident [
        $($heightmap_id:ident $heightmap_name:literal $heightmap_predicate:ident),*
        $(,)?
    ]) => {

        $($global_vis static $heightmap_id: $crate::heightmap::HeightmapType = $crate::heightmap::HeightmapType {
            name: $heightmap_name,
            predicate: $heightmap_predicate
        };)*

        $global_vis static $static_id: [&'static $crate::heightmap::HeightmapType; $crate::count!($($heightmap_id)*)] = [
            $(&$heightmap_id),*
        ];

    };
}