From 6b94db8140fa29c2e088f697a2907ea0e6cd8a1d Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 3 Nov 2019 16:57:26 +0000 Subject: [PATCH] Chunk Loading --- resources/shaders/simple.frag | 7 +- src/common.hpp | 3 +- src/game.cpp | 9 +-- src/renderer/renderer.cpp | 8 +-- src/world/chunk/chunk.cpp | 109 ++++++++++++++++++++---------- src/world/chunk/chunk.hpp | 16 ++++- src/world/entity.hpp | 1 + src/world/world.cpp | 120 +++++++++++++++++++++++++++++++++- src/world/world.hpp | 39 +++++++++-- 9 files changed, 253 insertions(+), 59 deletions(-) diff --git a/resources/shaders/simple.frag b/resources/shaders/simple.frag index ea822ac..949c2ec 100644 --- a/resources/shaders/simple.frag +++ b/resources/shaders/simple.frag @@ -17,8 +17,11 @@ void main() { if (outColour.w == .0) discard; - float fogMax = 20000; + float fogMax = 60000; - outColour = vec4(mix(outColour.xyz, SkyColour, min(1.0f, Distance / fogMax)), outColour.w); + vec3 colour = mix(outColour.xyz, SkyColour, min(1.0f, Distance / fogMax)); + + // Retain fragment transparency + outColour = vec4(colour, outColour.w); } diff --git a/src/common.hpp b/src/common.hpp index fce0036..fae97b2 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,9 +1,10 @@ #ifndef MINECRAFT_COMMON_H_ #define MINECRAFT_COMMON_H_ -#include #include #include +#include +#include #include #include diff --git a/src/game.cpp b/src/game.cpp index 60922ff..8182bcc 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,5 +1,8 @@ #include "game.hpp" +// For glm::vec2 as the key of a hashmap +#define GLM_ENABLE_EXPERIMENTAL + #define LOGGER_DEFINITION #include @@ -81,6 +84,8 @@ void Game::Setup(int w, int h) { m_cameras["Default"] = std::make_shared(w, h); m_activeCamera = m_cameras["Default"]; + m_activeCamera->Position = { 0, 40, 0 }; + m_activeCamera->UpdateView(); std::shared_ptr BlockDictionary = CBlockDictionary::GetInstance(); @@ -92,10 +97,6 @@ void Game::Setup(int w, int h) { m_world->SetTextureMap(texture.LoadTextures(BlockDictionary->Textures)); m_world->LoadWorld(); - - m_world->Shaders["Basic"] = std::make_shared(); - m_world->Shaders["Basic"]->Load(GameConfig.ResourceBase + "shaders/simple"); - m_world->Shaders["Basic"]->Link(); } diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 890a505..8cb01f3 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -11,12 +11,6 @@ Renderer::Renderer() { // Perform the render passes void Renderer::Render(std::shared_ptr world, std::shared_ptr camera) { - glBindTexture(GL_TEXTURE_2D_ARRAY, world->TextureID); - - for (int i = 0; i < world->Chunks.size(); i++) { - - world->Chunks[i]->Render(camera, world->Shaders["Basic"]); - - } + world->Render(camera); } diff --git a/src/world/chunk/chunk.cpp b/src/world/chunk/chunk.cpp index fe97a11..247895a 100644 --- a/src/world/chunk/chunk.cpp +++ b/src/world/chunk/chunk.cpp @@ -11,16 +11,43 @@ static std::default_random_engine generator; +Chunk::Chunk() { + +} + Chunk::Chunk(int x, int z) { m_model = glm::translate(glm::mat4(1.0f), { x * CHUNK_WIDTH, 0, z * CHUNK_DEPTH }); + + Load(); + +} + +Chunk::Chunk(int x, int z, std::vector voxels) { + + m_model = glm::translate(glm::mat4(1.0f), { x * CHUNK_WIDTH, 0, z * CHUNK_DEPTH }); + Voxels = voxels; + Load(); + +} + +void Chunk::Load() { + + if (Loaded) + return; + + if (!Voxels.empty()) { + m_mesh(); + return; + } + // [x + WIDTH * (y + HEIGHT * z)] for (int x = 0; x < CHUNK_WIDTH; x++) for (int y = 0; y < CHUNK_HEIGHT; y++) for (int z = 0; z < CHUNK_DEPTH; z++) { - + if (y > 32) { Voxels.push_back((uint8_t)EBlockType::Air); continue; @@ -28,13 +55,12 @@ Chunk::Chunk(int x, int z) { std::uniform_real_distribution distribution(0, 1); float r = distribution(generator); - - if (r > 0.8f) { + + if (r > 0.9f) { Voxels.push_back((uint8_t)EBlockType::Air); continue; } - if (y == 0) Voxels.push_back((uint8_t)EBlockType::Bedrock); else if (y < 28) @@ -47,22 +73,51 @@ Chunk::Chunk(int x, int z) { } m_mesh(); + Loaded = true; } -Chunk::Chunk(int x, int z, std::vector voxels) { +void Chunk::UploadMesh() { - m_model = glm::translate(glm::mat4(1.0f), { x * CHUNK_WIDTH, 0, z * CHUNK_DEPTH }); - - Voxels = voxels; - - m_mesh(); + if (!MeshReady) + return; + + glGenVertexArrays(1, &m_vao); + glBindVertexArray(m_vao); + + glGenBuffers(1, &m_vbo); + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + + std::vector data; + data.insert(data.end(), m_vertices.begin(), m_vertices.end()); + data.insert(data.end(), m_uvs.begin(), m_uvs.end()); + + m_numVerts = m_vertices.size(); + + glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(glm::vec3), &data[0], GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const void*)0); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const void*)(m_vertices.size() * sizeof(glm::vec3))); + + m_vertices.clear(); + m_uvs.clear(); + + data.clear(); + + glBindVertexArray(0); + + MeshReady = !MeshReady; } - void Chunk::Render(std::shared_ptr camera, std::shared_ptr shader) { + if (!Loaded) + return; + shader->Use(); glBindVertexArray(m_vao); @@ -79,8 +134,9 @@ void Chunk::Render(std::shared_ptr camera, std::shared_ptr shade } -void Chunk::Update() { +void Chunk::Update(std::vector voxels) { + Voxels = voxels; m_mesh(); } @@ -142,29 +198,10 @@ void Chunk::m_mesh() { } - glGenVertexArrays(1, &m_vao); - glBindVertexArray(m_vao); - - glGenBuffers(1, &m_vbo); - glBindBuffer(GL_ARRAY_BUFFER, m_vbo); - - std::vector data; - data.insert(data.end(), m_vertices.begin(), m_vertices.end()); - data.insert(data.end(), m_uvs.begin(), m_uvs.end()); - - m_numVerts = m_vertices.size(); - - glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(glm::vec3), &data[0], GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const void*)0); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const void*)(m_vertices.size() * sizeof(glm::vec3))); - - m_vertices.clear(); - m_uvs.clear(); - - glBindVertexArray(0); + MeshReady = true; + +} + +Chunk::~Chunk() { } diff --git a/src/world/chunk/chunk.hpp b/src/world/chunk/chunk.hpp index 82d54c3..16ae9b3 100644 --- a/src/world/chunk/chunk.hpp +++ b/src/world/chunk/chunk.hpp @@ -15,12 +15,19 @@ class Voxel; class Chunk { public: + Chunk(); Chunk(int x, int z); Chunk(int x, int z, std::vector voxels); + void Load(); + + bool MeshReady = false; + void UploadMesh(); + + void Render(std::shared_ptr camera, std::shared_ptr shader); - void Update(); + void Update(std::vector voxels); //bool Loaded = false; //bool Render = false; @@ -32,6 +39,13 @@ public: // to generate a mesh and send it to the GPU std::vector Voxels; + // To only be changed by the class its self + bool Loaded = false; + // To only be changed by render components + bool ShouldRender = false; + + ~Chunk(); + private: void m_mesh(); diff --git a/src/world/entity.hpp b/src/world/entity.hpp index f589403..7848976 100644 --- a/src/world/entity.hpp +++ b/src/world/entity.hpp @@ -2,3 +2,4 @@ #define MINECRAFT_WORLD_ENTITY_H_ +#endif diff --git a/src/world/world.cpp b/src/world/world.cpp index a28203b..7c0b10c 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -1,22 +1,140 @@ #include "world.hpp" +#include "chunk/chunk.hpp" + +#include "../renderer/shader.hpp" + +#include "../config.hpp" + World::World() { } void World::LoadWorld() { + + m_shaders["Basic"] = std::make_shared(); + m_shaders["Basic"]->Load(GameConfig.ResourceBase + "shaders/simple"); + m_shaders["Basic"]->Link(); + + for (int x = -4; x < 4; x++) + for (int y = -4; y < 4; y++) { + + m_chunkLoaderQueue.push({ x, y }); + + } + + for (int i = 0; i < 7; i++) { + + m_generatorThreads.push_back(std::thread([&]() { + + m_loadChunks(); + + })); + + } + + m_generatorRunning = true; } void World::SetTextureMap(GLuint map) { + m_textureMapID = map; + } -glm::vec2 World::GetChunkCoords(glm::vec3) { +glm::vec2 World::GetChunkCoords(glm::vec3 wordCoords) { + + return { wordCoords.x / CHUNK_WIDTH, wordCoords.z / CHUNK_DEPTH }; } std::vector> World::GetRenderableChunks() { + std::vector> chunks; + + for (auto& chunk : m_chunks) { + + // Should the chunk be rendererd ? + if (chunk.second->ShouldRender) { + + m_chunkMutex.lock(); + + if (chunk.second->MeshReady) + chunk.second->UploadMesh(); + + m_chunkMutex.unlock(); + + // If not, add it + chunks.push_back(chunk.second); + + } + + } + + return chunks; + } +void World::Render(std::shared_ptr camera) { + + glBindTexture(GL_TEXTURE_2D_ARRAY, m_textureMapID); + + std::vector> chunks = GetRenderableChunks(); + + + for (int i = 0; i < chunks.size(); i++) { + + chunks[i]->Render(camera, m_shaders["Basic"]); + + } + +} + +World::~World() { + + m_generatorRunning = false; + + for (int i = 0; i < m_generatorThreads.size(); i++) { + + m_generatorThreads[i].join(); + + } + +} + +void World::m_loadChunks() { + + while (m_generatorRunning) { + + m_chunkMutex.lock(); + + glm::vec2 coords = m_chunkLoaderQueue.front(); + m_chunkLoaderQueue.pop(); + + m_chunkMutex.unlock(); + + + std::shared_ptr loadingChunk = std::make_shared(coords.x, coords.y); + std::cout << "Loaded chunk " << coords.x << ":" << coords.y << std::endl; + + + m_chunkMutex.lock(); + + m_chunks[coords] = loadingChunk; + m_chunks[coords]->ShouldRender = true; + + m_chunkMutex.unlock(); + + + while (m_chunkLoaderQueue.empty()) { + + if (!m_generatorRunning) break; + static std::chrono::milliseconds dura(1); + std::this_thread::sleep_for(dura); + + } + + } + +} diff --git a/src/world/world.hpp b/src/world/world.hpp index 4a0d070..49826d3 100644 --- a/src/world/world.hpp +++ b/src/world/world.hpp @@ -3,42 +3,67 @@ #include "../common.hpp" -#include +#include "../renderer/camera.hpp" +#include "chunk/chunk.hpp" + +#include #include +#include +#include class Shader; -class Chunk; class World { public: + // Default constructor World(); + + // Preps the render threads and loads all of the shaders void LoadWorld(); void SetTextureMap(GLuint map); // Takes world coordinates and gets a chunks coordinates - glm::vec2 GetChunkCoords(glm::vec3); + glm::vec2 GetChunkCoords(glm::vec3 wordCoords); std::vector> GetRenderableChunks(); + + void Render(std::shared_ptr camera); + + ~World(); + private: + // GL stuff + + // Main texture map id GLuint m_textureMapID; - + // Shaders indexed by name std::map> m_shaders; - + + // Threads used for chunk generation std::vector m_generatorThreads; + bool m_generatorRunning = false; + // Chuks - - std::vector> m_renderableChunks; + // Indexed by chunk coorinates std::unordered_map> m_chunks; + std::queue m_chunkUpdatesQueue; + std::queue m_chunkLoaderQueue; + + std::mutex m_chunkMutex; + + + void m_loadChunks(); + }; #endif