From fdbe207540541b26d2800f87ddd77006d5fdf4f3 Mon Sep 17 00:00:00 2001 From: tylermurphy534 Date: Wed, 28 Sep 2022 19:36:35 -0400 Subject: [PATCH] async chunk generation --- src/chunk.cpp | 78 +++++++++++++++++++++++++++++++---------------- src/chunk.hpp | 9 ++++-- src/first_app.cpp | 7 ++--- src/first_app.hpp | 2 +- 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/chunk.cpp b/src/chunk.cpp index 395aee7..2f7c969 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -12,7 +12,6 @@ Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed) gridX{gridX}, gridZ{gridZ} { chunkMesh = nullptr; - generate(); } Chunk::~Chunk() { @@ -98,6 +97,7 @@ void Chunk::unload() { void Chunk::createMeshAsync(Chunk* c) { if(c == nullptr) return; if(c->working) return; + c->working = true; if(c->worker.joinable()) c->worker.join(); c->worker = std::thread(createMesh, c); @@ -105,6 +105,13 @@ void Chunk::createMeshAsync(Chunk* c) { void Chunk::createMesh(Chunk* c) { if(c == nullptr) return; + if(!isGenerated(c->gridX-1, c->gridZ) || + !isGenerated(c->gridX+1, c->gridZ) || + !isGenerated(c->gridX, c->gridZ-1) || + !isGenerated(c->gridX, c->gridZ+1)) { + c->working = false; + return; + } c->vertexData.data.clear(); for(int32_t x=0;x<16;x++) { for(int32_t y=0; y<256; y++) { @@ -132,8 +139,8 @@ void Chunk::createMesh(Chunk* c) { } } } + c->reload = true; c->working = false; - c->reloadRequired = true; } void Chunk::addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block) { @@ -150,12 +157,48 @@ void Chunk::addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z } } +// +// CHUNK GENERATION FOR BOTH SYNC AND ASYNC +// + +void Chunk::generateAsync(Chunk* c) { + if(c == nullptr) return; + if(c->working) return; + c->working = true; + if(c->worker.joinable()) + c->worker.join(); + c->worker = std::thread(generate, c); +} + +void Chunk::generate(Chunk* c) { + c->cubes.resize(16*16*256); + + const PerlinNoise perlin{c->world_seed}; + + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + int height = perlin.octave2D_01((( x + c->gridX * 16) * 0.01), ((z + c->gridZ * 16) * 0.01), 4) * 20; + for(int y = 0; y < 256; y++) { + if(y == height){ + c->setBlock(x, y, z, GRASS); + } else if(y < height) + c->setBlock(x, y, z, DIRT); + else + c->setBlock(x, y, z, AIR); + } + } + } + + c->generated = true; + c->working = false; +} + // // CHUNK GETTERS AND SETTORS // xe::Model* Chunk::getMesh() { - if(reloadRequired) { + if(reload) { if(chunkMesh != nullptr) { xe::Model::deleteModel(chunkMesh); chunkMesh = nullptr; @@ -166,7 +209,8 @@ xe::Model* Chunk::getMesh() { builder.vertexData = vertexData; builder.vertexSize = 36; chunkMesh = xe::Model::createModel(builder); - reloadRequired = false; + vertexData.data.clear(); + reload = false; } return chunkMesh; } @@ -207,28 +251,10 @@ void Chunk::setBlock(int32_t x, int32_t y, int32_t z, uint8_t block) { cubes[index] = block; } -// -// CHUNK GENERATION -// - -void Chunk::generate() { - cubes.resize(16*16*256); - - const PerlinNoise perlin{world_seed}; - - for(int x = 0; x < 16; x++) { - for(int z = 0; z < 16; z++) { - int height = perlin.octave2D_01((( x + gridX * 16) * 0.01), ((z + gridZ * 16) * 0.01), 4) * 20; - for(int y = 0; y < 256; y++) { - if(y == height){ - setBlock(x, y, z, GRASS); - } else if(y < height) - setBlock(x, y, z, DIRT); - else - setBlock(x, y, z, AIR); - } - } - } +bool Chunk::isGenerated(int32_t gridX, int32_t gridZ) { + Chunk* chunk = Chunk::getChunk(gridX, gridZ); + if(chunk == nullptr) return false; + return chunk->generated; } } \ No newline at end of file diff --git a/src/chunk.hpp b/src/chunk.hpp index c53a0d3..734c07b 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -44,10 +44,15 @@ class Chunk { static void createMesh(Chunk* c); static void createMeshAsync(Chunk* c); + static void generate(Chunk* c); + static void generateAsync(Chunk* c); + xe::Model* getMesh(); uint8_t getBlock(int32_t x, int32_t y, int32_t z); void setBlock(int32_t x, int32_t y, int32_t z, uint8_t block); + static bool isGenerated(int32_t gridX, int32_t gridZ); + const int32_t gridX, gridZ; const uint32_t world_seed, chunk_seed; @@ -56,10 +61,10 @@ class Chunk { Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed); ~Chunk(); - void generate(); static void addVerticies(Chunk* c, uint8_t side, int32_t x, int32_t y, int32_t z, uint8_t block); - bool reloadRequired{false}; + bool generated{false}; + bool reload{false}; bool working{false}; xe::Model* chunkMesh; diff --git a/src/first_app.cpp b/src/first_app.cpp index 6b6a80e..e677d06 100755 --- a/src/first_app.cpp +++ b/src/first_app.cpp @@ -78,11 +78,10 @@ void FirstApp::reloadLoadedChunks(xe::GameObject& viewer) { Chunk* chunk = Chunk::getChunk(newGridX, newGridZ); if(chunk == nullptr) { chunk = Chunk::newChunk(newGridX, newGridZ, 12345); + Chunk::generateAsync(chunk); + } + if(chunk->getMesh() == nullptr){ Chunk::createMeshAsync(chunk); - Chunk::createMeshAsync(Chunk::getChunk(newGridX+1, newGridZ)); - Chunk::createMeshAsync(Chunk::getChunk(newGridX-1, newGridZ)); - Chunk::createMeshAsync(Chunk::getChunk(newGridX, newGridZ+1)); - Chunk::createMeshAsync(Chunk::getChunk(newGridX, newGridZ-1)); } gameObject.model = chunk->getMesh(); gameObject.transform.translation = glm::vec3(newGridX * 16.f, 0, newGridZ * 16.f); diff --git a/src/first_app.hpp b/src/first_app.hpp index d361296..dc912fb 100755 --- a/src/first_app.hpp +++ b/src/first_app.hpp @@ -32,7 +32,7 @@ class FirstApp { static constexpr int WIDTH = 800; static constexpr int HEIGHT = 600; - static constexpr int RENDER_DISTANCE = 10; + static constexpr int RENDER_DISTANCE = 15; void createGameObjects(xe::GameObject& viewer); void reloadLoadedChunks(xe::GameObject& viewer);