veloren_common/figure/
cell.rs

1use crate::vol::FilledVox;
2use num_traits::FromPrimitive;
3use serde::{Deserialize, Serialize};
4use vek::*;
5
6#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, num_derive::FromPrimitive)]
7#[repr(u8)]
8pub enum CellSurface {
9    Matte = 0,
10    Glowy = 1,
11    Shiny = 2,
12    Fire = 3,
13    Water = 4,
14}
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(from = "CellSurface")]
18// Bits
19// 0..5 = CellSurface
20// 5..7 = Fill (0 = empty, 1 = hollow, 2 = filled, 3 = override hollow)
21pub struct CellAttr(u8);
22
23impl From<CellSurface> for CellAttr {
24    fn from(surf: CellSurface) -> Self { Self::filled(surf, false) }
25}
26
27impl CellAttr {
28    const EMPTY: u8 = 0 << 5;
29    const FILLED: u8 = 2 << 5;
30    const FILL_MASK: u8 = 0b11 << 5;
31    const HOLLOW: u8 = 1 << 5;
32    const OVERRIDE: u8 = 3 << 5;
33
34    #[inline]
35    fn empty(is_hollow: bool) -> Self { Self(if is_hollow { Self::HOLLOW } else { Self::EMPTY }) }
36
37    #[inline]
38    fn filled(surf: CellSurface, is_override: bool) -> Self {
39        Self(
40            surf as u8
41                | if is_override {
42                    Self::OVERRIDE
43                } else {
44                    Self::FILLED
45                },
46        )
47    }
48
49    #[inline]
50    pub fn get_surf(&self) -> Option<CellSurface> {
51        if self.is_filled() {
52            CellSurface::from_u8(self.0 & 0b11111)
53        } else {
54            None
55        }
56    }
57
58    #[inline]
59    pub fn is_filled(&self) -> bool {
60        matches!(self.0 & Self::FILL_MASK, Self::FILLED | Self::OVERRIDE)
61    }
62
63    #[inline]
64    pub fn is_override_hollow(&self) -> bool { self.0 & Self::FILL_MASK == Self::OVERRIDE }
65
66    #[inline]
67    pub fn is_hollowing(&self) -> bool { self.0 & Self::FILL_MASK == Self::HOLLOW }
68}
69
70/// A type representing a single voxel in a figure.
71#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
72pub struct Cell {
73    attr: CellAttr,
74    #[serde(default)]
75    col: Rgb<u8>,
76}
77
78const _: () = assert!(4 == std::mem::size_of::<Cell>());
79const _: () = assert!(1 == std::mem::align_of::<Cell>());
80
81impl Cell {
82    #[inline]
83    pub fn empty() -> Self {
84        Self {
85            col: Rgb::zero(),
86            attr: CellAttr::empty(false),
87        }
88    }
89
90    #[inline]
91    pub fn filled(col: Rgb<u8>, surf: CellSurface) -> Self {
92        Self {
93            col,
94            attr: CellAttr::filled(surf, false),
95        }
96    }
97
98    #[inline]
99    pub fn from_index(index: u8, col: Rgb<u8>) -> Cell {
100        match index {
101            8..13 => Self::filled(col, CellSurface::Shiny),
102            13..16 => Self::filled(col, CellSurface::Glowy),
103            16 => Self {
104                col,
105                attr: CellAttr::empty(true),
106            },
107            17..22 => Self {
108                col,
109                attr: CellAttr::filled(CellSurface::Matte, true),
110            },
111            _ => Self::filled(col, CellSurface::Matte),
112        }
113    }
114
115    #[inline]
116    pub fn get_color(&self) -> Option<Rgb<u8>> {
117        if self.is_filled() {
118            Some(self.col)
119        } else {
120            None
121        }
122    }
123
124    /// Transform cell colors
125    #[must_use]
126    pub fn map_rgb(mut self, transform: impl Fn(Rgb<u8>) -> Rgb<u8>) -> Self {
127        self.col = transform(self.col);
128        self
129    }
130}
131
132impl core::ops::Deref for Cell {
133    type Target = CellAttr;
134
135    fn deref(&self) -> &Self::Target { &self.attr }
136}
137
138impl FilledVox for Cell {
139    #[inline]
140    fn default_non_filled() -> Self { Cell::empty() }
141
142    #[inline]
143    fn is_filled(&self) -> bool { self.attr.is_filled() }
144}