summary refs log tree commit diff
path: root/src/World/Generation/ChunkMeshing.cpp
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-07-07 21:39:42 +0200
committerMel <einebeere@gmail.com>2023-07-07 21:39:42 +0200
commitf1fc192ddc4c739fa8b4b376c759b7d3218a34eb (patch)
tree9e9afb9a21ba3ca27d1f25d46230aa9d27f8be39 /src/World/Generation/ChunkMeshing.cpp
parent24b8124469350d1c80d0553cf3f4bf58cdb1489b (diff)
downloadmeowcraft-f1fc192ddc4c739fa8b4b376c759b7d3218a34eb.tar.zst
meowcraft-f1fc192ddc4c739fa8b4b376c759b7d3218a34eb.zip
Chunk-bound tree decoration
Diffstat (limited to 'src/World/Generation/ChunkMeshing.cpp')
-rw-r--r--src/World/Generation/ChunkMeshing.cpp183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/World/Generation/ChunkMeshing.cpp b/src/World/Generation/ChunkMeshing.cpp
new file mode 100644
index 0000000..54abc85
--- /dev/null
+++ b/src/World/Generation/ChunkMeshing.cpp
@@ -0,0 +1,183 @@
+#include "ChunkMeshing.hpp"
+
+namespace MC::World::Generation {
+
+std::array<Vector<2>, 4> face_tex_coords(BlockType type, BlockSide side) {
+    uint8_t atlas_width = 4;
+    uint8_t atlas_height = 4;
+
+    float width_step = 1.0f / atlas_width;
+    float height_step = 1.0f / atlas_height;
+
+    auto block_coords = [=](uint8_t x, uint8_t y) {
+        auto t = y * height_step;
+        auto l = x * width_step;
+        auto b = t + height_step;
+        auto r = l + width_step;
+
+        return std::array<Vector<2>, 4>{{
+            {l, b}, {r, b}, {r, t}, {l, t},
+        }};
+    };
+
+    switch (type) {
+        case BlockType::Dirt:
+            return block_coords(1, 0);
+        case BlockType::Grass:
+            switch (side) {
+                case BlockSide::Front:
+                case BlockSide::Back:
+                case BlockSide::Left:
+                case BlockSide::Right:
+                    return block_coords(2, 0);
+                case BlockSide::Bottom:
+                    return block_coords(1, 0);
+                case BlockSide::Top:
+                    return block_coords(0, 0);
+            }
+        case BlockType::Stone:
+            return block_coords(3, 0);
+        case BlockType::Sand:
+            return block_coords(1, 1);
+        case BlockType::Water:
+            return block_coords(0, 1);
+        case BlockType::Snow:
+            switch (side) {
+                case BlockSide::Front:
+                case BlockSide::Back:
+                case BlockSide::Left:
+                case BlockSide::Right:
+                    return block_coords(3, 1);
+                case BlockSide::Bottom:
+                    return block_coords(1, 0);
+                case BlockSide::Top:
+                    return block_coords(2, 1);
+            }
+        case BlockType::Wood:
+            switch (side) {
+                case BlockSide::Front:
+                case BlockSide::Back:
+                case BlockSide::Right:
+                case BlockSide::Left:
+                    return block_coords(0, 2);
+                case BlockSide::Bottom:
+                case BlockSide::Top:
+                    return block_coords(1, 2);
+            }
+        case BlockType::Leaves:
+            return block_coords(2, 2);
+        case BlockType::Air:
+            return {};
+    }
+}
+
+std::array<Vector<3>, 4> face_normals(BlockSide side) {
+    auto is_side = [=](BlockSide s) -> float { return s == side; };
+
+    Vector<3> normal = {
+        is_side(BlockSide::Right) - is_side(BlockSide::Left),
+        is_side(BlockSide::Top) - is_side(BlockSide::Bottom),
+        is_side(BlockSide::Front) - is_side(BlockSide::Back),
+    };
+
+    return {normal, normal, normal, normal};
+}
+
+bool is_face_visible(Chunk& chunk, ChunkMeshing::ChunkNeighbors neighbors, uint32_t x, uint32_t y, uint32_t z, BlockSide side) {
+    Vector<3, int32_t> offset{};
+    switch (side) {
+        case BlockSide::Front:
+            offset[2] = 1;
+            break;
+        case BlockSide::Back:
+            offset[2] = -1;
+            break;
+        case BlockSide::Top:
+            offset[1] = 1;
+            break;
+        case BlockSide::Bottom:
+            offset[1] = -1;
+            break;
+        case BlockSide::Left:
+            offset[0] = -1;
+            break;
+        case BlockSide::Right:
+            offset[0] = 1;
+            break;
+    }
+
+    Vector<3, int32_t> neighbor_pos{
+        (int32_t)x + offset.x(), (int32_t)y + offset.y(), (int32_t)z + offset.z(),
+    };
+
+    Chunk* chunk_to_ask;
+
+    if (neighbor_pos.z() < 0) {
+        chunk_to_ask = &neighbors.north;
+        neighbor_pos.z() += Chunk::Width;
+    } else if (neighbor_pos.x() >= (int32_t)Chunk::Width) {
+        chunk_to_ask = &neighbors.east;
+        neighbor_pos.x() -= Chunk::Width;
+    } else if (neighbor_pos.z() >= (int32_t)Chunk::Width) {
+        chunk_to_ask = &neighbors.south;
+        neighbor_pos.z() -= Chunk::Width;
+    } else if (neighbor_pos.x() < 0) {
+        chunk_to_ask = &neighbors.west;
+        neighbor_pos.x() += Chunk::Width;
+    } else {
+        chunk_to_ask = &chunk;
+    }
+
+    auto neighbor = chunk_to_ask->get(neighbor_pos.x(), neighbor_pos.y(), neighbor_pos.z());
+    if (neighbor.type == BlockType::Air) {
+        return true;
+    }
+
+    return false;
+}
+
+GFX::Mesh ChunkMeshing::create_mesh_for_chunk(Chunk& chunk, ChunkMeshing::ChunkNeighbors neighbors) {
+    std::vector<Vector<3>> positions{};
+    std::vector<Vector<3>> normals{};
+    std::vector<Vector<2>> tex_coords{};
+    std::vector<uint32_t> indices{};
+
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int y = 0; y < Chunk::Height; y++) {
+            for (int z = 0; z < Chunk::Width; z++) {
+                auto type = chunk.get(x, y, z).type;
+                if (type == BlockType::Air) {
+                    continue;
+                }
+
+                for (auto side: BlockSide::all()) {
+                    if (!is_face_visible(chunk, neighbors, x, y, z, side)) {
+                        continue;
+                    }
+
+                    auto side_positions = side.face();
+                    auto side_normals = face_normals(side);
+                    auto side_tex_coords = face_tex_coords(type, side);
+
+                    for (auto& position : side_positions) {
+                        position = position + Vector<3>{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)};
+                    }
+
+                    uint32_t s = positions.size();
+
+                    positions.insert(positions.end(), side_positions.begin(), side_positions.end());
+                    normals.insert(normals.end(), side_normals.begin(), side_normals.end());
+                    tex_coords.insert(tex_coords.end(), side_tex_coords.begin(), side_tex_coords.end());
+                    indices.insert(indices.end(), {s, s + 1, s + 3, s + 1, s + 2, s + 3});
+                }
+            }
+        }
+    }
+
+    return {
+        {positions, normals, tex_coords},
+        indices,
+    };
+}
+
+}
\ No newline at end of file