veloren_common/figure/
cell.rs1use 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")]
19pub 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#[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 #[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}