bones3_remesh/mesh/block_model.rs
1//! Defines how a block model should be added to a chunk mesh.
2
3use bevy::prelude::*;
4use bitflags::bitflags;
5use bones3_core::prelude::*;
6
7use crate::vertex_data::{ShapeBuilder, TempMesh};
8
9bitflags! {
10 #[derive(Copy, Clone)]
11 /// A bitflag-based enum that defines how a block is currently being occluded.
12 pub struct BlockOcclusion: u8 {
13 /// If true, the block is occluded in the negative X direction.
14 const NEG_X = 0b00000001;
15
16 /// If true, the block is occluded in the positive X direction.
17 const POS_X = 0b00000010;
18
19 /// If true, the block is occluded in the negative Y direction.
20 const NEG_Y = 0b00000100;
21
22 /// If true, the block is occluded in the positive Y direction.
23 const POS_Y = 0b00001000;
24
25 /// If true, the block is occluded in the negative Z direction.
26 const NEG_Z = 0b00010000;
27
28 /// If true, the block is occluded in the positive Z direction.
29 const POS_Z = 0b00100000;
30 }
31}
32
33impl BlockOcclusion {
34 /// Converts this block occlusion value into a directional offset vector.
35 pub fn into_offset(self) -> IVec3 {
36 let mut offset = IVec3::ZERO;
37
38 if self.contains(BlockOcclusion::NEG_X) {
39 offset += IVec3::NEG_X;
40 }
41
42 if self.contains(BlockOcclusion::POS_X) {
43 offset += IVec3::X;
44 }
45
46 if self.contains(BlockOcclusion::NEG_Y) {
47 offset += IVec3::NEG_Y;
48 }
49
50 if self.contains(BlockOcclusion::POS_Y) {
51 offset += IVec3::Y;
52 }
53
54 if self.contains(BlockOcclusion::NEG_Z) {
55 offset += IVec3::NEG_Z;
56 }
57
58 if self.contains(BlockOcclusion::POS_Z) {
59 offset += IVec3::Z;
60 }
61
62 offset
63 }
64
65 /// Gets the opposite facing value for this block occlusion.
66 ///
67 /// For a positive value along an axis, this function will return the
68 /// negative value of that axis. Likewise, negative value will return
69 /// the positive counter parts. This effect is applied for all defined
70 /// directional values.
71 pub fn opposite_face(self) -> BlockOcclusion {
72 let mut value = BlockOcclusion::empty();
73
74 if self.contains(BlockOcclusion::NEG_X) {
75 value |= BlockOcclusion::POS_X;
76 }
77
78 if self.contains(BlockOcclusion::POS_X) {
79 value |= BlockOcclusion::NEG_X;
80 }
81
82 if self.contains(BlockOcclusion::NEG_Y) {
83 value |= BlockOcclusion::POS_Y;
84 }
85
86 if self.contains(BlockOcclusion::POS_Y) {
87 value |= BlockOcclusion::NEG_Y;
88 }
89
90 if self.contains(BlockOcclusion::NEG_Z) {
91 value |= BlockOcclusion::POS_Z;
92 }
93
94 if self.contains(BlockOcclusion::POS_Z) {
95 value |= BlockOcclusion::NEG_Z;
96 }
97
98 value
99 }
100}
101
102impl Default for BlockOcclusion {
103 fn default() -> Self {
104 BlockOcclusion::empty()
105 }
106}
107
108/// A generator for creating a block model that can be written to a temporary
109/// chunk mesh.
110pub trait BlockModelGenerator {
111 /// Writes the block model to the provided temporary chunk mesh.
112 fn write_to_mesh(&self, mesh: &mut TempMesh, pos: IVec3);
113}
114
115/// A trait that can be defined for a block data object in order to specify how
116/// a block model should be generated and added to the chunk mesh.
117pub trait BlockShape: BlockData {
118 /// Writes an instance of this block shape to the provided shape builder,
119 ///
120 /// Information such as the current block occlusion may be retrieved from
121 /// the shape builder as needed.
122 fn write_shape(&self, shape_builder: &mut ShapeBuilder);
123
124 /// Checks if one tile is to occlude another tile. Returns True if face is
125 /// occluded.
126 fn check_occlude(&self, face: BlockOcclusion, other: Self) -> bool;
127}