diff options
| author | Mel <einebeere@gmail.com> | 2023-07-07 21:39:42 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2023-07-07 21:39:42 +0200 |
| commit | f1fc192ddc4c739fa8b4b376c759b7d3218a34eb (patch) | |
| tree | 9e9afb9a21ba3ca27d1f25d46230aa9d27f8be39 /src/World/Generation/ChunkMeshing.cpp | |
| parent | 24b8124469350d1c80d0553cf3f4bf58cdb1489b (diff) | |
| download | meowcraft-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.cpp | 183 |
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 |
