]> git.localhorst.tv Git - blank.git/blob - src/model/shape.cpp
use collision structures for ray tests
[blank.git] / src / model / shape.cpp
1 #include "Shape.hpp"
2 #include "shapes.hpp"
3
4
5 namespace blank {
6
7 void Shape::Vertices(
8         EntityModel::Buffer &out,
9         float tex_offset
10 ) const {
11         for (const auto &pos : vtx_pos) {
12                 out.vertices.emplace_back(pos);
13         }
14         for (const auto &coord : vtx_tex_coords) {
15                 out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset);
16         }
17         for (const auto &nrm : vtx_nrm) {
18                 out.normals.emplace_back(nrm);
19         }
20         for (auto idx : vtx_idx) {
21                 out.indices.emplace_back(idx);
22         }
23 }
24
25 void Shape::Vertices(
26         EntityModel::Buffer &out,
27         const glm::mat4 &transform,
28         float tex_offset,
29         EntityModel::Index idx_offset
30 ) const {
31         for (const auto &pos : vtx_pos) {
32                 out.vertices.emplace_back(transform * glm::vec4(pos, 1.0f));
33         }
34         for (const auto &coord : vtx_tex_coords) {
35                 out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset);
36         }
37         for (const auto &nrm : vtx_nrm) {
38                 out.normals.emplace_back(transform * glm::vec4(nrm, 0.0f));
39         }
40         for (auto idx : vtx_idx) {
41                 out.indices.emplace_back(idx_offset + idx);
42         }
43 }
44
45 void Shape::Vertices(
46         BlockModel::Buffer &out,
47         const glm::mat4 &transform,
48         float tex_offset,
49         BlockModel::Index idx_offset
50 ) const {
51         for (const auto &pos : vtx_pos) {
52                 out.vertices.emplace_back(transform * glm::vec4(pos, 1.0f));
53         }
54         for (const auto &coord : vtx_tex_coords) {
55                 out.tex_coords.emplace_back(coord.x, coord.y, coord.z + tex_offset);
56         }
57         for (auto idx : vtx_idx) {
58                 out.indices.emplace_back(idx_offset + idx);
59         }
60 }
61
62 void Shape::Outline(
63         OutlineModel::Buffer &out,
64         const OutlineModel::Position &elem_offset,
65         OutlineModel::Index idx_offset
66 ) const {
67         for (const auto &pos : out_pos) {
68                 out.vertices.emplace_back(elem_offset + pos);
69         }
70         for (auto idx : out_idx) {
71                 out.indices.emplace_back(idx_offset + idx);
72         }
73 }
74
75 void Shape::SetShape(
76         const EntityModel::Positions &pos,
77         const EntityModel::Normals &nrm,
78         const EntityModel::Indices &idx
79 ) {
80         vtx_pos = pos;
81         vtx_nrm = nrm;
82         vtx_idx = idx;
83 }
84
85 void Shape::SetTexture(
86         const BlockModel::TexCoords &tex_coords
87 ) {
88         vtx_tex_coords = tex_coords;
89 }
90
91 void Shape::SetOutline(
92         const OutlineModel::Positions &pos,
93         const OutlineModel::Indices &idx
94 ) {
95         out_pos = pos;
96         out_idx = idx;
97 }
98
99
100 NullShape::NullShape()
101 : Shape() {
102
103 }
104
105 bool NullShape::Intersects(
106         const Ray &,
107         const glm::mat4 &,
108         float &, glm::vec3 &
109 ) const noexcept {
110         return false;
111 }
112
113 bool NullShape::Intersects(
114         const glm::mat4 &,
115         const AABB &,
116         const glm::mat4 &,
117         float &,
118         glm::vec3 &
119 ) const noexcept {
120         return false;
121 }
122
123
124 CuboidShape::CuboidShape(const AABB &b)
125 : Shape()
126 , bb(b) {
127         bb.Adjust();
128         SetShape({
129                 { bb.min.x, bb.min.y, bb.max.z }, // front
130                 { bb.max.x, bb.min.y, bb.max.z },
131                 { bb.min.x, bb.max.y, bb.max.z },
132                 { bb.max.x, bb.max.y, bb.max.z },
133                 { bb.min.x, bb.min.y, bb.min.z }, // back
134                 { bb.min.x, bb.max.y, bb.min.z },
135                 { bb.max.x, bb.min.y, bb.min.z },
136                 { bb.max.x, bb.max.y, bb.min.z },
137                 { bb.min.x, bb.max.y, bb.min.z }, // top
138                 { bb.min.x, bb.max.y, bb.max.z },
139                 { bb.max.x, bb.max.y, bb.min.z },
140                 { bb.max.x, bb.max.y, bb.max.z },
141                 { bb.min.x, bb.min.y, bb.min.z }, // bottom
142                 { bb.max.x, bb.min.y, bb.min.z },
143                 { bb.min.x, bb.min.y, bb.max.z },
144                 { bb.max.x, bb.min.y, bb.max.z },
145                 { bb.min.x, bb.min.y, bb.min.z }, // left
146                 { bb.min.x, bb.min.y, bb.max.z },
147                 { bb.min.x, bb.max.y, bb.min.z },
148                 { bb.min.x, bb.max.y, bb.max.z },
149                 { bb.max.x, bb.min.y, bb.min.z }, // right
150                 { bb.max.x, bb.max.y, bb.min.z },
151                 { bb.max.x, bb.min.y, bb.max.z },
152                 { bb.max.x, bb.max.y, bb.max.z },
153         }, {
154                 {  0.0f,  0.0f,  1.0f }, // front
155                 {  0.0f,  0.0f,  1.0f },
156                 {  0.0f,  0.0f,  1.0f },
157                 {  0.0f,  0.0f,  1.0f },
158                 {  0.0f,  0.0f, -1.0f }, // back
159                 {  0.0f,  0.0f, -1.0f },
160                 {  0.0f,  0.0f, -1.0f },
161                 {  0.0f,  0.0f, -1.0f },
162                 {  0.0f,  1.0f,  0.0f }, // top
163                 {  0.0f,  1.0f,  0.0f },
164                 {  0.0f,  1.0f,  0.0f },
165                 {  0.0f,  1.0f,  0.0f },
166                 {  0.0f, -1.0f,  0.0f }, // bottom
167                 {  0.0f, -1.0f,  0.0f },
168                 {  0.0f, -1.0f,  0.0f },
169                 {  0.0f, -1.0f,  0.0f },
170                 { -1.0f,  0.0f,  0.0f }, // left
171                 { -1.0f,  0.0f,  0.0f },
172                 { -1.0f,  0.0f,  0.0f },
173                 { -1.0f,  0.0f,  0.0f },
174                 {  1.0f,  0.0f,  0.0f }, // right
175                 {  1.0f,  0.0f,  0.0f },
176                 {  1.0f,  0.0f,  0.0f },
177                 {  1.0f,  0.0f,  0.0f },
178         }, {
179                   0,  1,  2,  2,  1,  3, // front
180                   4,  5,  6,  6,  5,  7, // back
181                   8,  9, 10, 10,  9, 11, // top
182                  12, 13, 14, 14, 13, 15, // bottom
183                  16, 17, 18, 18, 17, 19, // left
184                  20, 21, 22, 22, 21, 23, // right
185         });
186         SetTexture({
187                 { 0.0f, 1.0f, 0.0f }, // front
188                 { 1.0f, 1.0f, 0.0f },
189                 { 0.0f, 0.0f, 0.0f },
190                 { 1.0f, 0.0f, 0.0f },
191                 { 1.0f, 1.0f, 0.0f }, // back
192                 { 1.0f, 0.0f, 0.0f },
193                 { 0.0f, 1.0f, 0.0f },
194                 { 0.0f, 0.0f, 0.0f },
195                 { 0.0f, 0.0f, 0.0f }, // top
196                 { 0.0f, 1.0f, 0.0f },
197                 { 1.0f, 0.0f, 0.0f },
198                 { 1.0f, 1.0f, 0.0f },
199                 { 1.0f, 0.0f, 0.0f }, // bottom
200                 { 0.0f, 0.0f, 0.0f },
201                 { 1.0f, 1.0f, 0.0f },
202                 { 0.0f, 1.0f, 0.0f },
203                 { 0.0f, 1.0f, 0.0f }, // left
204                 { 1.0f, 1.0f, 0.0f },
205                 { 0.0f, 0.0f, 0.0f },
206                 { 1.0f, 0.0f, 0.0f },
207                 { 1.0f, 1.0f, 0.0f }, // right
208                 { 1.0f, 0.0f, 0.0f },
209                 { 0.0f, 1.0f, 0.0f },
210                 { 0.0f, 0.0f, 0.0f },
211         });
212         SetOutline({
213                 { bb.min.x, bb.min.y, bb.min.z }, // back
214                 { bb.max.x, bb.min.y, bb.min.z },
215                 { bb.min.x, bb.max.y, bb.min.z },
216                 { bb.max.x, bb.max.y, bb.min.z },
217                 { bb.min.x, bb.min.y, bb.max.z }, // front
218                 { bb.max.x, bb.min.y, bb.max.z },
219                 { bb.min.x, bb.max.y, bb.max.z },
220                 { bb.max.x, bb.max.y, bb.max.z },
221         }, {
222                 0, 1, 1, 3, 3, 2, 2, 0, // back
223                 4, 5, 5, 7, 7, 6, 6, 4, // front
224                 0, 4, 1, 5, 2, 6, 3, 7, // sides
225         });
226 }
227
228 bool CuboidShape::Intersects(
229         const Ray &ray,
230         const glm::mat4 &M,
231         float &dist, glm::vec3 &normal
232 ) const noexcept {
233         return Intersection(ray, bb, M, &dist, &normal);
234 }
235
236 bool CuboidShape::Intersects(
237         const glm::mat4 &M,
238         const AABB &box,
239         const glm::mat4 &box_M,
240         float &depth,
241         glm::vec3 &normal
242 ) const noexcept {
243         return Intersection(bb, M, box, box_M, depth, normal);
244 }
245
246
247 StairShape::StairShape(const AABB &bb, const glm::vec2 &clip)
248 : Shape()
249 , top({ { bb.min.x, clip.y, bb.min.z }, { bb.max.x, bb.max.y, clip.x } })
250 , bot({ bb.min, { bb.max.x, clip.y, bb.max.z } }) {
251         SetShape({
252                 { top.min.x, top.min.y, top.max.z }, // front, upper
253                 { top.max.x, top.min.y, top.max.z },
254                 { top.min.x, top.max.y, top.max.z },
255                 { top.max.x, top.max.y, top.max.z },
256                 { bot.min.x, bot.min.y, bot.max.z }, // front, lower
257                 { bot.max.x, bot.min.y, bot.max.z },
258                 { bot.min.x, bot.max.y, bot.max.z },
259                 { bot.max.x, bot.max.y, bot.max.z },
260                 { bot.min.x, bot.min.y, bot.min.z }, // back
261                 { bot.min.x, top.max.y, bot.min.z },
262                 { top.max.x, bot.min.y, bot.min.z },
263                 { top.max.x, top.max.y, bot.min.z },
264                 { top.min.x, top.max.y, top.min.z }, // top, upper
265                 { top.min.x, top.max.y, top.max.z },
266                 { top.max.x, top.max.y, top.min.z },
267                 { top.max.x, top.max.y, top.max.z },
268                 { bot.min.x, bot.max.y, top.max.z }, // top, lower
269                 { bot.min.x, bot.max.y, bot.max.z },
270                 { bot.max.x, bot.max.y, top.max.z },
271                 { bot.max.x, bot.max.y, bot.max.z },
272                 { bot.min.x, bot.min.y, bot.min.z }, // bottom
273                 { bot.max.x, bot.min.y, bot.min.z },
274                 { bot.min.x, bot.min.y, bot.max.z },
275                 { bot.max.x, bot.min.y, bot.max.z },
276                 { top.min.x, top.min.y, top.min.z }, // left, upper
277                 { top.min.x, top.min.y, top.max.z },
278                 { top.min.x, top.max.y, top.min.z },
279                 { top.min.x, top.max.y, top.max.z },
280                 { bot.min.x, bot.min.y, bot.min.z }, // left, lower
281                 { bot.min.x, bot.min.y, bot.max.z },
282                 { bot.min.x, bot.max.y, bot.min.z },
283                 { bot.min.x, bot.max.y, bot.max.z },
284                 { top.max.x, top.min.y, top.min.z }, // right, upper
285                 { top.max.x, top.max.y, top.min.z },
286                 { top.max.x, top.min.y, top.max.z },
287                 { top.max.x, top.max.y, top.max.z },
288                 { bot.max.x, bot.min.y, bot.min.z }, // right, lower
289                 { bot.max.x, bot.max.y, bot.min.z },
290                 { bot.max.x, bot.min.y, bot.max.z },
291                 { bot.max.x, bot.max.y, bot.max.z },
292         }, {
293                 {  0.0f,  0.0f,  1.0f }, // front x2
294                 {  0.0f,  0.0f,  1.0f },
295                 {  0.0f,  0.0f,  1.0f },
296                 {  0.0f,  0.0f,  1.0f },
297                 {  0.0f,  0.0f,  1.0f },
298                 {  0.0f,  0.0f,  1.0f },
299                 {  0.0f,  0.0f,  1.0f },
300                 {  0.0f,  0.0f,  1.0f },
301                 {  0.0f,  0.0f, -1.0f }, // back
302                 {  0.0f,  0.0f, -1.0f },
303                 {  0.0f,  0.0f, -1.0f },
304                 {  0.0f,  0.0f, -1.0f },
305                 {  0.0f,  1.0f,  0.0f }, // top x2
306                 {  0.0f,  1.0f,  0.0f },
307                 {  0.0f,  1.0f,  0.0f },
308                 {  0.0f,  1.0f,  0.0f },
309                 {  0.0f,  1.0f,  0.0f },
310                 {  0.0f,  1.0f,  0.0f },
311                 {  0.0f,  1.0f,  0.0f },
312                 {  0.0f,  1.0f,  0.0f },
313                 {  0.0f, -1.0f,  0.0f }, // bottom
314                 {  0.0f, -1.0f,  0.0f },
315                 {  0.0f, -1.0f,  0.0f },
316                 {  0.0f, -1.0f,  0.0f },
317                 { -1.0f,  0.0f,  0.0f }, // left x2
318                 { -1.0f,  0.0f,  0.0f },
319                 { -1.0f,  0.0f,  0.0f },
320                 { -1.0f,  0.0f,  0.0f },
321                 { -1.0f,  0.0f,  0.0f },
322                 { -1.0f,  0.0f,  0.0f },
323                 { -1.0f,  0.0f,  0.0f },
324                 { -1.0f,  0.0f,  0.0f },
325                 {  1.0f,  0.0f,  0.0f }, // right x2
326                 {  1.0f,  0.0f,  0.0f },
327                 {  1.0f,  0.0f,  0.0f },
328                 {  1.0f,  0.0f,  0.0f },
329                 {  1.0f,  0.0f,  0.0f },
330                 {  1.0f,  0.0f,  0.0f },
331                 {  1.0f,  0.0f,  0.0f },
332                 {  1.0f,  0.0f,  0.0f },
333         }, {
334                  0,  1,  2,  2,  1,  3, // front, upper
335                  4,  5,  6,  6,  5,  7, // front, lower
336                  8,  9, 10, 10,  9, 11, // back
337                 12, 13, 14, 14, 13, 15, // top, upper
338                 16, 17, 18, 18, 17, 19, // top, lower
339                 20, 21, 22, 22, 21, 23, // bottom
340                 24, 25, 26, 26, 25, 27, // left, upper
341                 28, 29, 30, 30, 29, 31, // left, lower
342                 32, 33, 34, 34, 33, 35, // right, upper
343                 36, 37, 38, 38, 37, 39, // right, lower
344         });
345         SetTexture({
346                 { 0.0f, 0.5f, 0.0f }, // front, upper
347                 { 1.0f, 0.5f, 0.0f },
348                 { 0.0f, 0.0f, 0.0f },
349                 { 1.0f, 0.0f, 0.0f },
350                 { 0.0f, 1.0f, 0.0f }, // front, lower
351                 { 1.0f, 1.0f, 0.0f },
352                 { 0.0f, 0.5f, 0.0f },
353                 { 1.0f, 0.5f, 0.0f },
354                 { 1.0f, 1.0f, 0.0f }, // back
355                 { 1.0f, 0.0f, 0.0f },
356                 { 0.0f, 1.0f, 0.0f },
357                 { 0.0f, 0.0f, 0.0f },
358                 { 0.0f, 0.0f, 0.0f }, // top, upper
359                 { 0.0f, 0.5f, 0.0f },
360                 { 1.0f, 0.0f, 0.0f },
361                 { 1.0f, 0.5f, 0.0f },
362                 { 0.0f, 0.5f, 0.0f }, // top, lower
363                 { 0.0f, 1.0f, 0.0f },
364                 { 1.0f, 0.5f, 0.0f },
365                 { 1.0f, 1.0f, 0.0f },
366                 { 1.0f, 0.0f, 0.0f }, // bottom
367                 { 0.0f, 0.0f, 0.0f },
368                 { 1.0f, 1.0f, 0.0f },
369                 { 0.0f, 1.0f, 0.0f },
370                 { 0.0f, 0.5f, 0.0f }, // left, upper
371                 { 0.5f, 0.5f, 0.0f },
372                 { 0.0f, 0.0f, 0.0f },
373                 { 0.5f, 0.0f, 0.0f },
374                 { 0.0f, 1.0f, 0.0f }, // left, lower
375                 { 1.0f, 1.0f, 0.0f },
376                 { 0.0f, 0.5f, 0.0f },
377                 { 1.0f, 0.5f, 0.0f },
378                 { 1.0f, 0.5f, 0.0f }, // right, upper
379                 { 1.0f, 0.0f, 0.0f },
380                 { 0.5f, 0.5f, 0.0f },
381                 { 0.5f, 0.0f, 0.0f },
382                 { 1.0f, 1.0f, 0.0f }, // right, lower
383                 { 1.0f, 0.5f, 0.0f },
384                 { 0.0f, 1.0f, 0.0f },
385                 { 0.0f, 0.5f, 0.0f },
386         });
387         SetOutline({
388                 { bot.min.x, bot.min.y, bot.min.z }, // bottom
389                 { bot.max.x, bot.min.y, bot.min.z },
390                 { bot.min.x, bot.min.y, bot.max.z },
391                 { bot.max.x, bot.min.y, bot.max.z },
392                 { bot.min.x, bot.max.y, top.max.z }, // middle
393                 { bot.max.x, bot.max.y, top.max.z },
394                 { bot.min.x, bot.max.y, bot.max.z },
395                 { bot.max.x, bot.max.y, bot.max.z },
396                 { top.min.x, top.max.y, top.min.z }, // top
397                 { top.max.x, top.max.y, top.min.z },
398                 { top.min.x, top.max.y, top.max.z },
399                 { top.max.x, top.max.y, top.max.z },
400         }, {
401                  0,  1,  1,  3,  3,  2,  2,  0, // bottom
402                  4,  5,  5,  7,  7,  6,  6,  4, // middle
403                  8,  9,  9, 11, 11, 10, 10 , 8, // top
404                  0,  8,  4, 10,  2,  6, // verticals, btf
405                  1,  9,  5, 11,  3,  7,
406         });
407 }
408
409 bool StairShape::Intersects(
410         const Ray &ray,
411         const glm::mat4 &M,
412         float &dist,
413         glm::vec3 &norm
414 ) const noexcept {
415         float top_dist, bot_dist;
416         glm::vec3 top_norm, bot_norm;
417         bool top_hit = Intersection(ray, top, M, &top_dist, &top_norm);
418         bool bot_hit = Intersection(ray, bot, M, &bot_dist, &bot_norm);
419
420         if (top_hit) {
421                 if (bot_hit) {
422                         if (top_dist < bot_dist) {
423                                 dist = top_dist;
424                                 norm = top_norm;
425                                 return true;
426                         } else {
427                                 dist = bot_dist;
428                                 norm = bot_norm;
429                                 return true;
430                         }
431                 } else {
432                         dist = top_dist;
433                         norm = top_norm;
434                         return true;
435                 }
436         } else if (bot_hit) {
437                 dist = bot_dist;
438                 norm = bot_norm;
439                 return true;
440         } else {
441                 return false;
442         }
443 }
444
445 bool StairShape::Intersects(
446         const glm::mat4 &M,
447         const AABB &box,
448         const glm::mat4 &box_M,
449         float &dist,
450         glm::vec3 &normal
451 ) const noexcept {
452         bool top_hit, bot_hit;
453         float top_dist, bot_dist;
454         glm::vec3 top_normal, bot_normal;
455
456         top_hit = Intersection(bot, M, box, box_M, top_dist, top_normal);
457         bot_hit = Intersection(top, M, box, box_M, bot_dist, bot_normal);
458
459         if (top_hit) {
460                 if (bot_hit && bot_dist < top_dist) {
461                         dist = bot_dist;
462                         normal = bot_normal;
463                         return true;
464                 } else {
465                         dist = top_dist;
466                         normal = top_normal;
467                         return true;
468                 }
469                 return true;
470         } else if (bot_hit) {
471                 dist = bot_dist;
472                 normal = bot_normal;
473                 return true;
474         } else {
475                 return false;
476         }
477 }
478
479 }