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}
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(from = "CellSurface")]
18pub 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#[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 #[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}