]> git.localhorst.tv Git - blank.git/blob - src/block.hpp
84efa4894b0dd9146d6f22b1c1b8e11dd7cffec0
[blank.git] / src / block.hpp
1 #ifndef BLANK_BLOCK_HPP_
2 #define BLANK_BLOCK_HPP_
3
4 #include "geometry.hpp"
5 #include "model.hpp"
6 #include "shape.hpp"
7
8 #include <vector>
9 #include <glm/glm.hpp>
10
11
12 namespace blank {
13
14 /// single 1x1x1 cube
15 struct Block {
16
17         using Type = unsigned short;
18         using Pos = glm::vec3;
19
20         enum Face {
21                 FACE_UP,
22                 FACE_DOWN,
23                 FACE_RIGHT,
24                 FACE_LEFT,
25                 FACE_FRONT,
26                 FACE_BACK,
27                 FACE_COUNT,
28         };
29         enum Turn {
30                 TURN_NONE,
31                 TURN_LEFT,
32                 TURN_AROUND,
33                 TURN_RIGHT,
34                 TURN_COUNT,
35         };
36
37         static constexpr int ORIENT_COUNT = FACE_COUNT * TURN_COUNT;
38
39         Type type;
40         unsigned char orient;
41
42         constexpr explicit Block(Type type = 0, Face face = FACE_UP, Turn turn = TURN_NONE) noexcept
43         : type(type), orient(face * TURN_COUNT + turn) { }
44
45         const glm::mat4 &Transform() const noexcept { return orient2transform[orient]; }
46
47         Face GetFace() const noexcept { return Face(orient / TURN_COUNT); }
48         void SetFace(Face face) noexcept { orient = face * TURN_COUNT + GetTurn(); }
49         Turn GetTurn() const noexcept { return Turn(orient % TURN_COUNT); }
50         void SetTurn(Turn turn) noexcept { orient = GetFace() * TURN_COUNT + turn; }
51
52         Face OrientedFace(Face f) const noexcept { return orient2face[orient][f]; }
53
54         static Face Opposite(Face f) noexcept {
55                 return Face(f ^ 1);
56         }
57
58         static int Axis(Face f) noexcept {
59                 switch (f) {
60                         case FACE_UP:
61                         case FACE_DOWN:
62                                 return 1;
63                         default:
64                         case FACE_RIGHT:
65                         case FACE_LEFT:
66                                 return 0;
67                         case FACE_FRONT:
68                         case FACE_BACK:
69                                 return 2;
70                 }
71         }
72
73         static glm::tvec3<int> FaceNormal(Face face) noexcept {
74                 return face2normal[face];
75         }
76
77         static Face NormalFace(const glm::vec3 &norm) noexcept {
78                 const glm::vec3 anorm(abs(norm));
79                 if (anorm.x > anorm.y) {
80                         if (anorm.x > anorm.z) {
81                                 return norm.x > 0.0f ? FACE_RIGHT : FACE_LEFT;
82                         } else {
83                                 return norm.z > 0.0f ? FACE_FRONT : FACE_BACK;
84                         }
85                 } else {
86                         if (anorm.y > anorm.z) {
87                                 return norm.y > 0.0f ? FACE_UP : FACE_DOWN;
88                         } else {
89                                 return norm.z > 0.0f ? FACE_FRONT : FACE_BACK;
90                         }
91                 }
92         }
93
94         struct FaceSet {
95
96                 explicit FaceSet(unsigned char v = 0)
97                 : value(v) { }
98
99                 bool IsSet(Face f) const {
100                         return value & Mask(f);
101                 }
102                 void Set(Face f) {
103                         value |= Mask(f);
104                 }
105                 void Unset(Face f) {
106                         value |= ~Mask(f);
107                 }
108
109                 void Clear() {
110                         value = 0;
111                 }
112                 void Fill() {
113                         value = Mask(FACE_COUNT) - 1;
114                 }
115
116                 bool Empty() const {
117                         return value == 0;
118                 }
119                 bool All() const {
120                         return value == Mask(FACE_COUNT) - 1;
121                 }
122
123                 unsigned char Mask(Face f) const {
124                         return 1 << f;
125                 }
126
127                 unsigned char value;
128
129         };
130
131 private:
132         static const glm::tvec3<int> face2normal[6];
133         static const glm::mat4 orient2transform[ORIENT_COUNT];
134         static const Face orient2face[ORIENT_COUNT][FACE_COUNT];
135
136 };
137
138
139 /// attributes of a type of block
140 struct BlockType {
141
142         const Shape *shape;
143         glm::vec3 color;
144         glm::vec3 outline_color;
145
146         Block::Type id;
147
148         int luminosity;
149
150         bool visible;
151         bool block_light;
152
153         struct Faces {
154                 bool face[Block::FACE_COUNT];
155                 Faces &operator =(const Faces &other) noexcept {
156                         for (int i = 0; i < Block::FACE_COUNT; ++i) {
157                                 face[i] = other.face[i];
158                         }
159                         return *this;
160                 }
161                 bool operator [](Block::Face f) const noexcept {
162                         return face[f];
163                 }
164         } fill;
165
166         explicit BlockType(
167                 bool v = false,
168                 const glm::vec3 &color = { 1, 1, 1 },
169                 const Shape *shape = &DEFAULT_SHAPE
170         ) noexcept;
171
172         static const NullShape DEFAULT_SHAPE;
173
174         bool FaceFilled(const Block &block, Block::Face face) const noexcept {
175                 return fill[block.OrientedFace(face)];
176         }
177
178         void FillModel(
179                 Model::Buffer &m,
180                 const glm::mat4 &transform = glm::mat4(1.0f),
181                 Model::Index idx_offset = 0
182         ) const noexcept;
183         void FillBlockModel(
184                 BlockModel::Buffer &m,
185                 const glm::mat4 &transform = glm::mat4(1.0f),
186                 BlockModel::Index idx_offset = 0
187         ) const noexcept;
188         void FillOutlineModel(
189                 OutlineModel &m,
190                 const glm::vec3 &pos_offset = { 0, 0, 0 },
191                 OutlineModel::Index idx_offset = 0
192         ) const noexcept;
193
194 };
195
196
197 class BlockTypeRegistry {
198
199 public:
200         BlockTypeRegistry();
201
202 public:
203         Block::Type Add(const BlockType &);
204
205         size_t Size() const noexcept { return types.size(); }
206
207         BlockType &operator [](Block::Type id) { return types[id]; }
208         const BlockType &Get(Block::Type id) const { return types[id]; }
209
210 private:
211         std::vector<BlockType> types;
212
213 };
214
215 }
216
217 #endif