summaryrefslogtreecommitdiff
path: root/src/World/Generation
diff options
context:
space:
mode:
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);
+
+}