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