]> git.localhorst.tv Git - blank.git/blob - src/model/shape.cpp
4943e6377c3525d0c21b0144f7a3384f74dd8f76
[blank.git] / src / model / shape.cpp
1 #include "Shape.hpp"
2 #include "ShapeRegistry.hpp"
3
4 #include "bounds.hpp"
5 #include "../io/TokenStreamReader.hpp"
6
7 #include <string>
8
9 using namespace std;
10
11
12 namespace blank {
13
14 Shape::Shape()
15 : bounds()
16 , vertices()
17 , indices()
18 , fill({ false, false, false, false, false, false }) {
19
20 }
21
22 void Shape::Read(TokenStreamReader &in) {
23         bounds.reset();
24         vertices.clear();
25         indices.clear();
26         fill = { false, false, false, false, false, false };
27
28         string name;
29         in.Skip(Token::ANGLE_BRACKET_OPEN);
30         while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
31                 in.ReadIdentifier(name);
32                 in.Skip(Token::EQUALS);
33                 if (name == "bounds") {
34                         string bounds_class;
35                         in.ReadIdentifier(bounds_class);
36                         in.Skip(Token::PARENTHESIS_OPEN);
37                         if (bounds_class == "Cuboid") {
38                                 glm::vec3 min;
39                                 glm::vec3 max;
40                                 in.ReadVec(min);
41                                 in.Skip(Token::COMMA);
42                                 in.ReadVec(max);
43                                 bounds.reset(new CuboidBounds(AABB{min, max}));
44                         } else if (bounds_class == "Stair") {
45                                 glm::vec3 min;
46                                 glm::vec3 max;
47                                 glm::vec2 split;
48                                 in.ReadVec(min);
49                                 in.Skip(Token::COMMA);
50                                 in.ReadVec(max);
51                                 in.Skip(Token::COMMA);
52                                 in.ReadVec(split);
53                                 bounds.reset(new StairBounds(AABB{min, max}, split));
54                         } else {
55                                 while (in.Peek().type != Token::PARENTHESIS_CLOSE) {
56                                         in.Next();
57                                 }
58                         }
59                         in.Skip(Token::PARENTHESIS_CLOSE);
60
61                 } else if (name == "vertices") {
62                         in.Skip(Token::ANGLE_BRACKET_OPEN);
63                         while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
64                                 in.Skip(Token::ANGLE_BRACKET_OPEN);
65                                 Vertex vtx;
66                                 in.ReadVec(vtx.position);
67                                 in.Skip(Token::COMMA);
68                                 in.ReadVec(vtx.normal);
69                                 in.Skip(Token::COMMA);
70                                 in.ReadVec(vtx.tex_st);
71                                 in.Skip(Token::COMMA);
72                                 in.ReadNumber(vtx.tex_id);
73                                 if (in.Peek().type == Token::COMMA) {
74                                         in.Skip(Token::COMMA);
75                                 }
76                                 in.Skip(Token::ANGLE_BRACKET_CLOSE);
77                                 if (in.Peek().type == Token::COMMA) {
78                                         in.Skip(Token::COMMA);
79                                 }
80                                 vertices.push_back(vtx);
81                         }
82                         in.Skip(Token::ANGLE_BRACKET_CLOSE);
83
84                 } else if (name == "indices") {
85                         in.Skip(Token::ANGLE_BRACKET_OPEN);
86                         while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
87                                 indices.push_back(in.GetULong());
88                                 if (in.Peek().type == Token::COMMA) {
89                                         in.Skip(Token::COMMA);
90                                 }
91                         }
92                         in.Skip(Token::ANGLE_BRACKET_CLOSE);
93
94                 } else if (name == "fill") {
95                         in.Skip(Token::BRACKET_OPEN);
96                         fill.face[Block::FACE_UP] = in.GetBool();
97                         in.Skip(Token::COMMA);
98                         fill.face[Block::FACE_DOWN] = in.GetBool();
99                         in.Skip(Token::COMMA);
100                         fill.face[Block::FACE_RIGHT] = in.GetBool();
101                         in.Skip(Token::COMMA);
102                         fill.face[Block::FACE_LEFT] = in.GetBool();
103                         in.Skip(Token::COMMA);
104                         fill.face[Block::FACE_FRONT] = in.GetBool();
105                         in.Skip(Token::COMMA);
106                         fill.face[Block::FACE_BACK] = in.GetBool();
107                         in.Skip(Token::BRACKET_CLOSE);
108
109                 } else {
110                         // try to skip, might fail though
111                         while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
112                                 in.Next();
113                         }
114                 }
115                 in.Skip(Token::SEMICOLON);
116         }
117         in.Skip(Token::ANGLE_BRACKET_CLOSE);
118 }
119
120 float Shape::TexR(const vector<float> &tex_map, size_t off) noexcept {
121         if (off < tex_map.size()) {
122                 return tex_map[off];
123         } else if (!tex_map.empty()) {
124                 return tex_map.back();
125         } else {
126                 return 0.0f;
127         }
128 }
129
130 void Shape::Fill(
131         EntityMesh::Buffer &buf,
132         const vector<float> &tex_map
133 ) const {
134         for (const auto &vtx : vertices) {
135                 buf.vertices.emplace_back(vtx.position);
136                 buf.normals.emplace_back(vtx.normal);
137                 buf.tex_coords.emplace_back(vtx.tex_st.s, vtx.tex_st.t, TexR(tex_map, vtx.tex_id));
138         }
139         for (auto idx : indices) {
140                 buf.indices.emplace_back(idx);
141         }
142 }
143
144 void Shape::Fill(
145         EntityMesh::Buffer &buf,
146         const glm::mat4 &transform,
147         const vector<float> &tex_map
148 ) const {
149         for (const auto &vtx : vertices) {
150                 buf.vertices.emplace_back(transform * glm::vec4(vtx.position, 1.0f));
151                 buf.normals.emplace_back(transform * glm::vec4(vtx.normal, 0.0f));
152                 buf.tex_coords.emplace_back(vtx.tex_st.s, vtx.tex_st.t, TexR(tex_map, vtx.tex_id));
153         }
154         for (auto idx : indices) {
155                 buf.indices.emplace_back(idx);
156         }
157 }
158
159 void Shape::Fill(
160         BlockMesh::Buffer &buf,
161         const glm::mat4 &transform,
162         const vector<float> &tex_map,
163         size_t idx_offset
164 ) const {
165         for (const auto &vtx : vertices) {
166                 buf.vertices.emplace_back(transform * glm::vec4(vtx.position, 1.0f));
167                 buf.tex_coords.emplace_back(vtx.tex_st.s, vtx.tex_st.t, TexR(tex_map, vtx.tex_id));
168         }
169         for (auto idx : indices) {
170                 buf.indices.emplace_back(idx_offset + idx);
171         }
172 }
173
174 size_t Shape::OutlineCount() const noexcept {
175         if (bounds) {
176                 return bounds->OutlineCount();
177         } else {
178                 return 0;
179         }
180 }
181
182 size_t Shape::OutlineIndexCount() const noexcept {
183         if (bounds) {
184                 return bounds->OutlineIndexCount();
185         } else {
186                 return 0;
187         }
188 }
189
190 void Shape::Outline(OutlineMesh::Buffer &out) const {
191         if (bounds) {
192                 bounds->Outline(out);
193         }
194 }
195
196 bool Shape::Intersects(
197         const Ray &ray,
198         const glm::mat4 &M,
199         float &dist,
200         glm::vec3 &normal
201 ) const noexcept {
202         if (bounds) {
203                 return bounds->Intersects(ray, M, dist, normal);
204         } else {
205                 return false;
206         }
207 }
208
209 bool Shape::Intersects(
210         const glm::mat4 &M,
211         const AABB &box,
212         const glm::mat4 &box_M,
213         float &depth,
214         glm::vec3 &normal
215 ) const noexcept {
216         if (bounds) {
217                 return bounds->Intersects(M, box, box_M, depth, normal);
218         } else {
219                 return false;
220         }
221 }
222
223
224 ShapeRegistry::ShapeRegistry()
225 : shapes() {
226
227 }
228
229 Shape &ShapeRegistry::Add(const string &name) {
230         auto result = shapes.emplace(name, Shape());
231         if (result.second) {
232                 return result.first->second;
233         } else {
234                 throw runtime_error("duplicate shape " + name);
235         }
236 }
237
238 Shape &ShapeRegistry::Get(const string &name) {
239         auto entry = shapes.find(name);
240         if (entry != shapes.end()) {
241                 return entry->second;
242         } else {
243                 throw runtime_error("unknown shape " + name);
244         }
245 }
246
247 const Shape &ShapeRegistry::Get(const string &name) const {
248         auto entry = shapes.find(name);
249         if (entry != shapes.end()) {
250                 return entry->second;
251         } else {
252                 throw runtime_error("unknown shape " + name);
253         }
254 }
255
256 }