summary refs log tree commit diff
path: root/src/World/Generation
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-07-21 02:17:03 +0200
committerMel <einebeere@gmail.com>2023-07-21 02:17:03 +0200
commit23d88e5f1c8f0c8652a07050fcfa8ff126e85d4a (patch)
treed2979c12a9675885b7ed969d5f51dbd69d969286 /src/World/Generation
parentc0556f76fc5c8271c2eaa7ca91ad1c92c691d8bc (diff)
downloadmeowcraft-23d88e5f1c8f0c8652a07050fcfa8ff126e85d4a.tar.zst
meowcraft-23d88e5f1c8f0c8652a07050fcfa8ff126e85d4a.zip
Extremely simple chunk-limited lighting
Diffstat (limited to 'src/World/Generation')
-rw-r--r--src/World/Generation/ChunkMeshing.cpp54
-rw-r--r--src/World/Generation/ChunkMeshing.hpp18
-rw-r--r--src/World/Generation/ChunkNeighbors.cpp34
-rw-r--r--src/World/Generation/ChunkNeighbors.hpp13
-rw-r--r--src/World/Generation/Decoration.cpp10
-rw-r--r--src/World/Generation/Generator.cpp13
-rw-r--r--src/World/Generation/Lighting.cpp20
-rw-r--r--src/World/Generation/Lighting.hpp13
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);
+
+}