diff options
Diffstat (limited to 'src/World/Generation')
| -rw-r--r-- | src/World/Generation/ChunkMeshing.cpp | 54 | ||||
| -rw-r--r-- | src/World/Generation/ChunkMeshing.hpp | 18 | ||||
| -rw-r--r-- | src/World/Generation/ChunkNeighbors.cpp | 34 | ||||
| -rw-r--r-- | src/World/Generation/ChunkNeighbors.hpp | 13 | ||||
| -rw-r--r-- | src/World/Generation/Decoration.cpp | 10 | ||||
| -rw-r--r-- | src/World/Generation/Generator.cpp | 13 | ||||
| -rw-r--r-- | src/World/Generation/Lighting.cpp | 20 | ||||
| -rw-r--r-- | src/World/Generation/Lighting.hpp | 13 |
8 files changed, 119 insertions, 56 deletions
diff --git a/src/World/Generation/ChunkMeshing.cpp b/src/World/Generation/ChunkMeshing.cpp index 2e9f191..002dd79 100644 --- a/src/World/Generation/ChunkMeshing.cpp +++ b/src/World/Generation/ChunkMeshing.cpp @@ -124,6 +124,14 @@ Face<Normal> DefaultMeshDecisions::face_normals(BlockSide side) { return {normal, normal, normal, normal}; } +Face<Light> DefaultMeshDecisions::face_light(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { + auto neighbor = get_opposing_neighbor(chunk, neighbors, x, y, z, side); + if (!neighbor.type.is_translucent()) return {}; + + auto light = (F32)neighbor.light / (F32)255; + return {light, light, light, light}; +} + Face<AO> DefaultMeshDecisions::face_ao_values(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { std::array<Vector<3, I32>, 8> offsets{}; // Given a block position, these offsets can be added to it to get the 8 blocks necessary to calculate AO. @@ -177,35 +185,6 @@ Face<AO> DefaultMeshDecisions::face_ao_values(Chunk& chunk, const ChunkNeighbors return vertex_ao; } -Chunk::BlockData DefaultMeshDecisions::get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos) { - const Chunk* chunk_to_ask; - - auto overflow = [](I32& c, I32 max) -> I8 { - if (c < 0) { c += max; return -1; } - if (c >= max) { c -= max; return 1; } - return 0; - }; - - auto xo = overflow(pos.x(), Chunk::Width); - auto yo = overflow(pos.y(), Chunk::Height); - auto zo = overflow(pos.z(), Chunk::Width); - - // Blocks above and below a chunk are always Air. - if (yo != 0) return {}; - - if (xo == 1 && zo == 1) { chunk_to_ask = neighbors.south_east; } - else if (xo == 1 && zo == -1) { chunk_to_ask = neighbors.north_east; } - else if (xo == -1 && zo == 1) { chunk_to_ask = neighbors.south_west; } - else if (xo == -1 && zo == -1) { chunk_to_ask = neighbors.north_west; } - else if (xo == 1) { chunk_to_ask = neighbors.east; } - else if (xo == -1) { chunk_to_ask = neighbors.west; } - else if (zo == 1) { chunk_to_ask = neighbors.south; } - else if (zo == -1) { chunk_to_ask = neighbors.north; } - else { chunk_to_ask = &chunk; } - - return chunk_to_ask->get(pos.x(), pos.y(), pos.z()); -} - Vector<3, I32> DefaultMeshDecisions::get_face_normal(BlockSide side) { auto is_side = [=](BlockSide s) -> I8 { return s == side; }; @@ -216,12 +195,16 @@ Vector<3, I32> DefaultMeshDecisions::get_face_normal(BlockSide side) { }; } -Bool DefaultMeshDecisions::is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { +Chunk::BlockData DefaultMeshDecisions::get_opposing_neighbor(const Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { Vector<3, I32> offset = get_face_normal(side); auto neighbor_position = offset + Vector<3, I32>{x, y, z}; - auto block = get_block_wrapping(chunk, neighbors, neighbor_position); - return block.type.is_transparent(); + return get_block_wrapping(chunk, neighbors, neighbor_position); +} + +Bool DefaultMeshDecisions::is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { + auto block = get_opposing_neighbor(chunk, neighbors, x, y, z, side); + return block.type.is_translucent(); } Bool DefaultMeshDecisions::should_ignore_block(Chunk::BlockData block) { @@ -229,11 +212,8 @@ Bool DefaultMeshDecisions::should_ignore_block(Chunk::BlockData block) { } Bool WaterMeshDecisions::is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { - Vector<3, I32> offset = get_face_normal(side); - auto neighbor_position = offset + Vector<3, I32>{x, y, z}; - - auto [neighbor] = get_block_wrapping(chunk, neighbors, neighbor_position); - return neighbor.is_transparent() && neighbor != BlockType::Water; + auto block = get_opposing_neighbor(chunk, neighbors, x, y, z, side); + return block.type.is_translucent() && block.type != BlockType::Water; } Bool WaterMeshDecisions::should_ignore_block(Chunk::BlockData block) { diff --git a/src/World/Generation/ChunkMeshing.hpp b/src/World/Generation/ChunkMeshing.hpp index 7e202ab..fb5fea9 100644 --- a/src/World/Generation/ChunkMeshing.hpp +++ b/src/World/Generation/ChunkMeshing.hpp @@ -2,15 +2,12 @@ #include "../../GFX/Mesh.hpp" #include "../../GFX/Util/MeshBuilder.hpp" +#include "../BlockSide.hpp" #include "../Chunk.hpp" +#include "ChunkNeighbors.hpp" namespace MC::World::Generation::ChunkMeshing { -struct ChunkNeighbors { - Chunk *north, *east, *south, *west; - Chunk *north_east, *south_east, *south_west, *north_west; -}; - struct ChunkMesh { GFX::Mesh land_mesh, water_mesh; }; ChunkMesh mesh_chunk(Chunk& chunk, const ChunkNeighbors& neighbors); @@ -19,6 +16,7 @@ namespace Detail { using Vertex = Vector<3, F32>; using Normal = Vector<3, F32>; using TexCoord = Vector<2, F32>; +using Light = F32; using AO = F32; template <typename T> @@ -26,12 +24,12 @@ using Face = std::array<T, 4>; template <typename Decisions> GFX::Mesh create_mesh(Chunk& chunk, const ChunkNeighbors& neighbors) { - GFX::Util::MeshBuilder<Normal, TexCoord, AO> builder; + GFX::Util::MeshBuilder<Normal, TexCoord, Light, AO> builder; 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 block = chunk.get(x, y, z); + auto block = chunk.at(x, y, z); if (Decisions::should_ignore_block(block)) continue; @@ -44,7 +42,8 @@ GFX::Mesh create_mesh(Chunk& chunk, const ChunkNeighbors& neighbors) { builder.positions(Decisions::face_positions(side, x, y, z)); builder.attributes<0>(Decisions::face_normals(side)); builder.attributes<1>(Decisions::face_tex_coords(block.type, side)); - builder.attributes<2>(Decisions::face_ao_values(chunk, neighbors, x, y, z, side)); + builder.attributes<2>(Decisions::face_light(chunk, neighbors, x, y, z, side)); + builder.attributes<3>(Decisions::face_ao_values(chunk, neighbors, x, y, z, side)); builder.indices(std::array{ s + 0, s + 1, s + 2, s + 2, s + 3, s + 0 }); } } @@ -59,10 +58,11 @@ public: static Face<Vertex> face_positions(BlockSide side, U32 x, U32 y, U32 z); static Face<TexCoord> face_tex_coords(BlockType type, BlockSide side); static Face<Normal> face_normals(BlockSide side); + static Face<Light> face_light(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side); static Face<AO> face_ao_values(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side); - static Chunk::BlockData get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos); static Vector<3, I32> get_face_normal(BlockSide side); + static Chunk::BlockData get_opposing_neighbor(const Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side); static Bool is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side); static Bool should_ignore_block(Chunk::BlockData block); diff --git a/src/World/Generation/ChunkNeighbors.cpp b/src/World/Generation/ChunkNeighbors.cpp new file mode 100644 index 0000000..f34466e --- /dev/null +++ b/src/World/Generation/ChunkNeighbors.cpp @@ -0,0 +1,34 @@ +#include "ChunkNeighbors.hpp" + +namespace MC::World::Generation { + +Chunk::BlockData get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos) { + const Chunk* chunk_to_ask; + + auto overflow = [](I32& c, I32 max) -> I8 { + if (c < 0) { c += max; return -1; } + if (c >= max) { c -= max; return 1; } + return 0; + }; + + auto xo = overflow(pos.x(), Chunk::Width); + auto yo = overflow(pos.y(), Chunk::Height); + auto zo = overflow(pos.z(), Chunk::Width); + + // Blocks above and below a chunk are always Air. + if (yo != 0) return {}; + + if (xo == 1 && zo == 1) { chunk_to_ask = neighbors.south_east; } + else if (xo == 1 && zo == -1) { chunk_to_ask = neighbors.north_east; } + else if (xo == -1 && zo == 1) { chunk_to_ask = neighbors.south_west; } + else if (xo == -1 && zo == -1) { chunk_to_ask = neighbors.north_west; } + else if (xo == 1) { chunk_to_ask = neighbors.east; } + else if (xo == -1) { chunk_to_ask = neighbors.west; } + else if (zo == 1) { chunk_to_ask = neighbors.south; } + else if (zo == -1) { chunk_to_ask = neighbors.north; } + else { chunk_to_ask = &chunk; } + + return chunk_to_ask->at(pos.x(), pos.y(), pos.z()); +} + +} \ No newline at end of file diff --git a/src/World/Generation/ChunkNeighbors.hpp b/src/World/Generation/ChunkNeighbors.hpp new file mode 100644 index 0000000..1207c60 --- /dev/null +++ b/src/World/Generation/ChunkNeighbors.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../Chunk.hpp" + +namespace MC::World::Generation { +struct ChunkNeighbors { + Chunk *north, *east, *south, *west; + Chunk *north_east, *south_east, *south_west, *north_west; +}; + +Chunk::BlockData get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos); + +} \ No newline at end of file diff --git a/src/World/Generation/Decoration.cpp b/src/World/Generation/Decoration.cpp index f3f7c46..bcabffa 100644 --- a/src/World/Generation/Decoration.cpp +++ b/src/World/Generation/Decoration.cpp @@ -7,8 +7,10 @@ void Decorator::put_block(Chunk& chunk, Pos pos, BlockType block) { if (!Chunk::is_valid_position(pos.x(), pos.y(), pos.z())) { return; } - if (chunk.is_empty(pos.x(), pos.y(), pos.z())) { - chunk.set(pos.x(), pos.y(), pos.z(), {block}); + + auto& place = chunk.at(pos.x(), pos.y(), pos.z()); + if (place.empty()) { + place = {block}; } } @@ -48,7 +50,7 @@ void TreeDecorator::decorate_chunk(Chunk& chunk) { if (!is_valid_position(pos)) continue; - auto block_below = chunk.get(x, y-1, z); + auto& block_below = chunk.at(x, y-1, z); if (block_below.empty()) continue; @@ -64,7 +66,7 @@ void TreeDecorator::decorate_chunk(Chunk& chunk) { continue; draw_tree(chunk, pos); - chunk.set(x, y-1, z, {BlockType::Dirt}); + block_below = {BlockType::Dirt}; last_tree = pos; break; } diff --git a/src/World/Generation/Generator.cpp b/src/World/Generation/Generator.cpp index 88e69a7..9d63fc1 100644 --- a/src/World/Generation/Generator.cpp +++ b/src/World/Generation/Generator.cpp @@ -24,7 +24,7 @@ Chunk Generator::generate(I64 chunk_x, I64 chunk_y) { } #define SIMPLE_MAP_GENERATOR(name, getter) \ -Generator::Map2D<Real> Generator::name(I64 chunk_x, I64 chunk_y) { \ +Generator::Map2D<Real> Generator::name(I64 chunk_x, I64 chunk_y) { \ Matrix<Chunk::Width, Chunk::Width> map{}; \ for (UInt x = 0; x < Chunk::Width; x++) { \ for (UInt y = 0; y < Chunk::Width; y++) { \ @@ -161,19 +161,20 @@ void Generator::decorate_soil(Chunk& chunk, Map2D<BiomeType>& biome_map, Map3D<B auto column_depth = 0; for (UInt y = Chunk::Height - 1; y > 0; y--) { + auto& place = chunk.at(x, y, z); auto block = terrain_map(x, y, z); if (block) { if (column_depth == 0 && y >= water_height - 1) { - chunk.set(x, y, z, {top_block}); + place = {top_block}; } else if (column_depth < dirt_depth) { - chunk.set(x, y, z, {soil_block}); + place = {soil_block}; } else { - chunk.set(x, y, z, {BlockType::Stone}); + place = {BlockType::Stone}; } column_depth++; } else { if (y < water_height) { - chunk.set(x, y, z, {BlockType::Water}); + place = {BlockType::Water}; } column_depth = 0; } @@ -181,7 +182,7 @@ void Generator::decorate_soil(Chunk& chunk, Map2D<BiomeType>& biome_map, Map3D<B } } - for (auto& decorator : s_decorators) { + for (auto decorator : s_decorators) { decorator->decorate_chunk(chunk); } } diff --git a/src/World/Generation/Lighting.cpp b/src/World/Generation/Lighting.cpp new file mode 100644 index 0000000..8df6e2a --- /dev/null +++ b/src/World/Generation/Lighting.cpp @@ -0,0 +1,20 @@ +#include "Lighting.hpp" + +namespace MC::World::Generation::Lighting { + +void light_chunk(Chunk& chunk, ChunkNeighbors& _) { + for (UInt x = 0; x < Chunk::Width; x++) { + for (UInt z = 0; z < Chunk::Width; z++) { + U8 current_light_exposure = LightSun; + for (UInt y = Chunk::Height - 1; y != 0; y--) { + auto& block = chunk.at(x, y, z); + if (!block.type.is_translucent()) break; + + current_light_exposure = (Real)current_light_exposure * (1 - block.type.opacity()); + block.light = current_light_exposure; + } + } + } +} + +} diff --git a/src/World/Generation/Lighting.hpp b/src/World/Generation/Lighting.hpp new file mode 100644 index 0000000..7bb8fcc --- /dev/null +++ b/src/World/Generation/Lighting.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "../Chunk.hpp" +#include "ChunkNeighbors.hpp" + +namespace MC::World::Generation::Lighting { + +constexpr U8 LightSun = 200; +constexpr U8 LightTorch = 100; + +void light_chunk(Chunk& chunk, ChunkNeighbors& neighbors); + +} |
