diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/Math/Mod.hpp | 12 | ||||
| -rw-r--r-- | src/World/ChunkIndex.hpp | 8 | ||||
| -rw-r--r-- | src/World/ChunkRegistry.cpp | 9 | ||||
| -rw-r--r-- | src/World/ChunkRegistry.hpp | 2 | ||||
| -rw-r--r-- | src/World/Generation/ChunkMeshing.cpp | 12 | ||||
| -rw-r--r-- | src/World/Generation/ChunkMeshing.hpp | 8 | ||||
| -rw-r--r-- | src/World/Position.hpp | 66 | ||||
| -rw-r--r-- | src/World/World.cpp | 7 |
9 files changed, 86 insertions, 39 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index de94623..c828d5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ add_executable(meowcraft src/World/ChunkRegistry.cpp src/World/ChunkRegistry.hpp src/World/Position.hpp src/World/ChunkDimensions.hpp + src/Math/Mod.hpp ) target_link_libraries(meowcraft glfw GLEW::GLEW) diff --git a/src/Math/Mod.hpp b/src/Math/Mod.hpp new file mode 100644 index 0000000..d686ad9 --- /dev/null +++ b/src/Math/Mod.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace Math { + +// Returns the least nonnegative remainder of a % b. +// Euclidian definition of modulo. +template <typename A, typename B> +auto mod(A a, B b) -> decltype(a % b) { + return (a % b + b) % b; +} + +} \ No newline at end of file diff --git a/src/World/ChunkIndex.hpp b/src/World/ChunkIndex.hpp index ed3347b..70de99f 100644 --- a/src/World/ChunkIndex.hpp +++ b/src/World/ChunkIndex.hpp @@ -16,11 +16,17 @@ struct ChunkIndex { return {(x + 0.5f) * Width, Height / 2.0f, (y + 0.5f) * Width}; } - Position::BlockWorld world(Position::BlockLocal local) const { + Position::BlockWorld local_to_world_position(Position::BlockLocal local) const { using namespace ChunkDimensions; return {x * Width + local.x(), local.y(), y * Width + local.z()}; } + static ChunkIndex from_position(Position::BlockWorld pos) { + I32 chunk_x = std::round(pos.x() / ChunkDimensions::Width); + I32 chunk_y = std::round(pos.z() / ChunkDimensions::Width); + return {chunk_x, chunk_y}; + } + I32 x, y; }; diff --git a/src/World/ChunkRegistry.cpp b/src/World/ChunkRegistry.cpp index 41fd1b0..97896fe 100644 --- a/src/World/ChunkRegistry.cpp +++ b/src/World/ChunkRegistry.cpp @@ -15,14 +15,11 @@ ChunkRegistry::Data& ChunkRegistry::get(ChunkIndex index) { } ChunkRegistry::Data& ChunkRegistry::find(Position::BlockWorld pos) { - return get({ - static_cast<I32>(pos.x() / Chunk::Width), - static_cast<I32>(pos.z() / Chunk::Width) - }); + return get(ChunkIndex::from_position(pos)); } -ChunkRegistry::Data& ChunkRegistry::find(ChunkIndex chunk, Position::BlockLocal pos) { - return find(chunk.world(pos)); +ChunkRegistry::Data& ChunkRegistry::find(Position::World pos) { + return find(pos.round_to_block()); } } \ No newline at end of file diff --git a/src/World/ChunkRegistry.hpp b/src/World/ChunkRegistry.hpp index 2c515c5..ea887e4 100644 --- a/src/World/ChunkRegistry.hpp +++ b/src/World/ChunkRegistry.hpp @@ -41,7 +41,7 @@ public: Data& get(ChunkIndex index); Data& find(Position::BlockWorld pos); - Data& find(ChunkIndex chunk, Position::BlockLocal pos); + Data& find(Position::World pos); private: std::unordered_map<ChunkIndex, Data> m_chunks; }; diff --git a/src/World/Generation/ChunkMeshing.cpp b/src/World/Generation/ChunkMeshing.cpp index 3855de4..feecc64 100644 --- a/src/World/Generation/ChunkMeshing.cpp +++ b/src/World/Generation/ChunkMeshing.cpp @@ -11,15 +11,15 @@ ChunkMesh mesh_chunk(Chunk& chunk, const SurroundingContext& context) { }; } -SurroundingContext::Block& SurroundingContext::at(Position::BlockOffset p) { +SurroundingContext::Block& SurroundingContext::at(Position::BlockLocalOffset p) { return m_blocks[pos(p)]; } -const SurroundingContext::Block& SurroundingContext::at(Position::BlockOffset p) const { +const SurroundingContext::Block& SurroundingContext::at(Position::BlockLocalOffset p) const { return m_blocks[pos(p)]; } -USize SurroundingContext::pos(Position::BlockOffset p) { +USize SurroundingContext::pos(Position::BlockLocalOffset p) { // First we calculate the index as if there were no gaps. USize pos = 0; pos += p.x() + 1; @@ -39,7 +39,7 @@ SurroundingContext create_meshing_context(const Chunk& chunk, ChunkNeighbors& ne for (I16 x = -1; x <= (I16)Chunk::Width; x++) { for (I16 z = -1; z <= (I16)Chunk::Width; z++) { for (I16 y = 0; y < (I16)Chunk::Height; y++) { - Position::BlockOffset pos{x, y, z}; + Position::BlockLocalOffset pos{x, y, z}; if (pos.fits_within_chunk()) continue; auto [does_exist, block] = get_block_wrapping(chunk, neighbors, {pos.x(), pos.y(), pos.z()}); context.at(pos) = {does_exist, block}; @@ -205,7 +205,7 @@ Face<AO> DefaultMeshDecisions::face_ao_values(Chunk& chunk, const SurroundingCon auto b = offsets[++offset_index]; // corner auto c = offsets[++offset_index % 8]; - auto p = [=](auto o) -> Position::BlockOffset { return {(I16)((I16)x + o.x()), (I16)((I16)y + o.y()), (I16)((I16)z + o.z())}; }; + auto p = [=](auto o) -> Position::BlockLocalOffset { return {(I16)x + o.x(), (I16)y + o.y(), (I16)z + o.z()}; }; auto block_a = get_block_from_chunk_or_context(chunk, context, p(a)); auto block_b = get_block_from_chunk_or_context(chunk, context, p(b)); auto block_c = get_block_from_chunk_or_context(chunk, context, p(c)); @@ -236,7 +236,7 @@ Vector<3, I32> DefaultMeshDecisions::get_face_normal(BlockSide side) { } SurroundingContext::Block DefaultMeshDecisions::get_block_from_chunk_or_context( - const Chunk& chunk, const SurroundingContext& context, Position::BlockOffset pos + const Chunk& chunk, const SurroundingContext& context, Position::BlockLocalOffset pos ) { if (pos.fits_within_chunk()) return {true, chunk.at(pos)}; return context.at(pos); diff --git a/src/World/Generation/ChunkMeshing.hpp b/src/World/Generation/ChunkMeshing.hpp index 5401580..c745a3b 100644 --- a/src/World/Generation/ChunkMeshing.hpp +++ b/src/World/Generation/ChunkMeshing.hpp @@ -19,10 +19,10 @@ class SurroundingContext { public: struct Block { Bool does_exist; Chunk::BlockData block; }; - Block& at(Position::BlockOffset p); - const Block& at(Position::BlockOffset p) const; + Block& at(Position::BlockLocalOffset p); + const Block& at(Position::BlockLocalOffset p) const; private: - static USize pos(Position::BlockOffset p); + static USize pos(Position::BlockLocalOffset p); static constexpr USize surrounding_block_count = Chunk::Width * 4 + 4; Block m_blocks[surrounding_block_count * Chunk::Height] = {}; @@ -83,7 +83,7 @@ public: static Face<AO> face_ao_values(Chunk& chunk, const SurroundingContext& context, U32 x, U32 y, U32 z, BlockSide side); static Vector<3, I32> get_face_normal(BlockSide side); - static SurroundingContext::Block get_block_from_chunk_or_context(const Chunk& chunk, const SurroundingContext& context, Position::BlockOffset pos); + static SurroundingContext::Block get_block_from_chunk_or_context(const Chunk& chunk, const SurroundingContext& context, Position::BlockLocalOffset pos); static SurroundingContext::Block get_opposing_neighbor(const Chunk& chunk, const SurroundingContext& context, U32 x, U32 y, U32 z, BlockSide side); static Bool is_face_visible(Chunk& chunk, const SurroundingContext& context, U32 x, U32 y, U32 z, BlockSide side); diff --git a/src/World/Position.hpp b/src/World/Position.hpp index 07de6f3..bc874c0 100644 --- a/src/World/Position.hpp +++ b/src/World/Position.hpp @@ -2,38 +2,36 @@ #include "array" #include "ChunkDimensions.hpp" +#include "../Math/Mod.hpp" +#include "../Math/Random.hpp" #include "../Math/Vector.hpp" namespace MC::Position { -// Position within entire world. -using World = Vector<3>; - -// Offset between two world positions. -using WorldOffset = Vector<3>; +#define MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(name, t) \ + name() = default; \ + template<typename ...Args, std::enable_if_t<sizeof...(Args) == 3, Int> = 0> \ + name(Args... args) : Vector{ static_cast<t>(args)... } {} \ + name(Vector v) : Vector(v) {} // Offset between block positions within single chunk. -class BlockOffset : public Vector<3, I16> { +class BlockLocalOffset : public Vector<3, I16> { public: - BlockOffset(I16 x, I16 y, I16 z) : Vector(x, y, z) {} + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(BlockLocalOffset, I16) + Bool fits_within_chunk() const { using namespace MC::World::ChunkDimensions; return x() >= 0 && x() < Width && y() >= 0 && y() < Height && z() >= 0 && z() < Width; } }; -// Position of a block within entire world. -class BlockWorld : public Vector<3, I64> { -public: - BlockWorld(I64 x, I64 y, I64 z) : Vector(x, y, z) {} -}; - // Position of a block within single chunk. class BlockLocal : public Vector<3, U8> { public: - BlockLocal(U8 x, U8 y, U8 z) : Vector(x, y, z) {} - BlockLocal(BlockOffset offset) : BlockLocal(offset.x(), offset.y(), offset.z()) {} - BlockOffset offset(BlockOffset by) { + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(BlockLocal, U8) + BlockLocal(BlockLocalOffset offset) : BlockLocal(offset.x(), offset.y(), offset.z()) {} + + BlockLocalOffset offset(BlockLocalOffset by) { return { static_cast<I8>(x() + by.x()), static_cast<I8>(y() + by.y()), @@ -42,8 +40,42 @@ public: } }; -const std::array<BlockOffset, 6> axis_directions = {{ +// Offset between block positions within entire world. +class BlockWorldOffset : public Vector<3, I64> { +public: + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(BlockWorldOffset, I64) +}; + +// Position of a block within entire world. +class BlockWorld : public Vector<3, I64> { +public: + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(BlockWorld, I64) + + BlockLocal to_local() const { + using namespace MC::World::ChunkDimensions; + return {Math::mod(x(), Width), y(), Math::mod(z(), Width)}; + } +}; + +const std::array<BlockLocalOffset, 6> axis_directions = {{ {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}, }}; +// Offset between two world positions. +class WorldOffset : public Vector<3> { +public: + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(WorldOffset, Real) +}; + +// Position within entire world. +class World : public Vector<3> { +public: + MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(World, Real) + + BlockWorld round_to_block() const { + auto rounded = map([](auto x) { return std::round(x); }); + return {rounded.x(), rounded.y(), rounded.z()}; + } +}; + } diff --git a/src/World/World.cpp b/src/World/World.cpp index 3ff0cf4..089c498 100644 --- a/src/World/World.cpp +++ b/src/World/World.cpp @@ -42,8 +42,7 @@ std::vector<ChunkRegistry::Data*> World::get_visible_chunks(Position::World posi } std::vector<ChunkIndex> World::get_visible_chunk_indices(const Position::World position) const { - I32 center_x = std::round(position.x() / Chunk::Width); - I32 center_y = std::round(position.z() / Chunk::Width); + ChunkIndex center = ChunkIndex::from_position(position.round_to_block()); std::vector<ChunkIndex> indices{}; indices.reserve(m_view_distance_radius * m_view_distance_radius * 4); @@ -52,8 +51,8 @@ std::vector<ChunkIndex> World::get_visible_chunk_indices(const Position::World p I32 height = std::round(std::sqrt(radius * radius - x * x) + 0.5); for (I32 y = -height; y <= height; y++) { // Needed so that this function and is_chunk_in_radius forcibly agree. - if (!is_chunk_in_radius(position, {x + center_x, y + center_y})) continue; - indices.emplace_back(x + center_x, y + center_y); + if (!is_chunk_in_radius(position, {x + center.x, y + center.y})) continue; + indices.emplace_back(x + center.x, y + center.y); } } |
