-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmesher.cpp
More file actions
104 lines (94 loc) · 3.61 KB
/
mesher.cpp
File metadata and controls
104 lines (94 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "mesher.h"
#include <array>
namespace {
enum class FaceDirection { front, right, left, back, bottom, top };
// 6 faces, 4 vertices per face, 3 components per vertex
// H--------G
// D--------C |
// | | | |
// | | | |
// | E----|-- F
// A--------B
constexpr glm::vec3 A{-1, -1, +1};
constexpr glm::vec3 B{+1, -1, +1};
constexpr glm::vec3 C{+1, +1, +1};
constexpr glm::vec3 D{-1, +1, +1};
constexpr glm::vec3 E{-1, -1, -1};
constexpr glm::vec3 F{+1, -1, -1};
constexpr glm::vec3 G{+1, +1, -1};
constexpr glm::vec3 H{-1, +1, -1};
struct Face {
FaceDirection direction;
glm::ivec3 neighbor_offset;
glm::vec3 vertices[4];
int indices[6];
glm::ivec2 texture[4]{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
};
// wind triangles counter-clockwise to face front. Each 6 element vector
// indexes into the four vertices that make up a face, defining two triangles
// that share two vertices.
constexpr std::array<Face, 6> kFaces{
{// front ACD, ABC (positive z)
{FaceDirection::front, {0, 0, 1}, {A, B, C, D}, {0, 2, 3, 0, 1, 2}},
// right BGC, BFG (positive x)
{FaceDirection::right, {1, 0, 0}, {F, B, C, G}, {1, 3, 2, 1, 0, 3}},
// left AHE, ADH (negative x)
{FaceDirection::left, {-1, 0, 0}, {E, A, D, H}, {1, 3, 0, 1, 2, 3}},
// back FHG, FEH (negative z)
{FaceDirection::back, {0, 0, -1}, {E, F, G, H}, {1, 3, 2, 1, 0, 3}},
// bottom AEF, AFB (negative y)
{FaceDirection::bottom, {0, -1, 0}, {E, A, B, F}, {1, 0, 3, 1, 3, 2}},
// top DCG, DGH (positive y)
{FaceDirection::top, {0, 1, 0}, {H, D, C, G}, {1, 2, 3, 1, 3, 0}}}};
float face_intensity(const FaceDirection direction) {
return direction == FaceDirection::front ? 0.7f
: direction == FaceDirection::right ? 0.5f
: 1.0f;
}
// the entire texture sample is 1 "logical" unit wide. It is split in 16 by
// 16 tiles, each a square 1/16 = 0.0625 units wide
constexpr float kTileWidth{0.0625f};
} // namespace
Mesh build_chunk_mesh(const Chunk &chunk, const glm::ivec2 chunk_pos,
const std::function<bool(glm::ivec3)> &is_solid_at_world) {
static_cast<void>(chunk_pos);
return build_mesh_from_cubes(chunk.cube_list(), is_solid_at_world);
}
Mesh build_mesh_from_cubes(
const std::vector<Cube> &cubes,
const std::function<bool(glm::ivec3)> &is_solid_at_world) {
Mesh mesh{};
for (const Cube &cube : cubes) {
const CubeTex &tex = cube.texture();
int face_index = 0;
for (const Face &face : kFaces) {
const glm::ivec3 neighbor_world = cube.world_pos + face.neighbor_offset;
if (!is_solid_at_world(neighbor_world)) {
const uint32_t base_index =
static_cast<uint32_t>(mesh.vertices.size());
const int tx{tex.t[face_index] % 16};
const int ty{tex.t[face_index] / 16};
const float du{kTileWidth * tx};
const float dv{kTileWidth * ty};
for (int i = 0; i < 4; i++) {
const glm::vec3 xyz = face.vertices[i];
const glm::ivec2 uv = face.texture[i];
mesh.vertices.push_back(Vertex{
glm::vec3{cube.world_pos.x + 0.5f * xyz.x,
cube.world_pos.y + 0.5f * xyz.y,
cube.world_pos.z + 0.5f * xyz.z},
glm::vec2{du + (uv.x ? kTileWidth : 0.0f),
dv + (uv.y ? kTileWidth : 0.0f)},
face_intensity(face.direction),
});
}
for (int idx : face.indices) {
mesh.indices.push_back(base_index +
static_cast<uint32_t>(idx));
}
}
face_index++;
}
}
return mesh;
}