procedural chunk loading
This commit is contained in:
parent
965ff9cc09
commit
9b60b862e5
12 changed files with 89 additions and 60 deletions
|
@ -32,24 +32,6 @@ void Engine::loadDescriptorPool() {
|
|||
.build();
|
||||
}
|
||||
|
||||
Model* Engine::loadModelFromFile(const std::string &filename) {
|
||||
return Model::createModelFromFile(xeDevice, filename);
|
||||
}
|
||||
|
||||
Model* Engine::loadModelFromData(std::vector<unsigned char> vertexData, uint32_t vertexSize, std::vector<uint32_t> indices) {
|
||||
Model::Builder builder{};
|
||||
builder.vertexData.data = vertexData;
|
||||
builder.vertexSize = vertexSize;
|
||||
if(indices.size() > 0) {
|
||||
builder.indices = indices;
|
||||
}
|
||||
return new Model(xeDevice, builder);
|
||||
}
|
||||
|
||||
Image* Engine::loadImageFromFile(const std::string &filename, bool anisotropic) {
|
||||
return new Image(xeDevice, filename, anisotropic);
|
||||
}
|
||||
|
||||
bool Engine::poll() {
|
||||
glfwPollEvents();
|
||||
auto newTime = std::chrono::high_resolution_clock::now();
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "xe_buffer.hpp"
|
||||
#include "xe_device.hpp"
|
||||
#include "xe_renderer.hpp"
|
||||
#include "xe_camera.hpp"
|
||||
#include "xe_descriptors.hpp"
|
||||
#include "xe_image.hpp"
|
||||
#include "xe_input.hpp"
|
||||
#include "xe_sound.hpp"
|
||||
#include "xe_model.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
@ -30,11 +29,6 @@ class Engine {
|
|||
|
||||
Input& getInput() {return xeInput;}
|
||||
Camera& getCamera() {return xeCamera;}
|
||||
Device& getDevice() {return xeDevice;}
|
||||
|
||||
Model* loadModelFromFile(const std::string &filename);
|
||||
Model* loadModelFromData(std::vector<unsigned char> vertexData, uint32_t vertexSize, std::vector<uint32_t> indices);
|
||||
Image* loadImageFromFile(const std::string &filename, bool anisotropic = true);
|
||||
|
||||
bool beginFrame() { return xeRenderer.beginFrame(); }
|
||||
void endFrame() { xeRenderer.endFrame(); }
|
||||
|
@ -63,6 +57,8 @@ class Engine {
|
|||
std::unique_ptr<DescriptorPool> xeDescriptorPool;
|
||||
|
||||
friend class RenderSystem;
|
||||
friend class Image;
|
||||
friend class Model;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include "xe_image.hpp"
|
||||
#include "xe_engine.hpp"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <stdexcept>
|
||||
|
@ -10,7 +11,7 @@
|
|||
|
||||
namespace xe {
|
||||
|
||||
Image::Image(Device &xeDevice, const std::string &filename, bool anisotropic) : xeDevice{xeDevice} {
|
||||
Image::Image(const std::string &filename, bool anisotropic) : xeDevice{Engine::getInstance()->xeDevice} {
|
||||
createTextureImage(filename);
|
||||
createTextureImageView();
|
||||
createTextureSampler(anisotropic);
|
||||
|
|
|
@ -10,7 +10,7 @@ class Image {
|
|||
|
||||
public:
|
||||
|
||||
Image(Device &xeDevice, const std::string &filename, bool anisotropic);
|
||||
Image(const std::string &filename, bool anisotropic);
|
||||
~Image();
|
||||
|
||||
Image(const Image&) = delete;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "xe_model.hpp"
|
||||
#include "xe_engine.hpp"
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "xe_obj_loader.hpp"
|
||||
|
@ -13,17 +14,17 @@
|
|||
|
||||
namespace xe {
|
||||
|
||||
Model::Model(Device &device, const Model::Builder &builder) : xeDevice{device} {
|
||||
Model::Model(const Model::Builder &builder) : xeDevice{Engine::getInstance()->xeDevice} {
|
||||
createVertexBuffers(builder.vertexData.data, builder.vertexSize);
|
||||
createIndexBuffers(builder.indices);
|
||||
}
|
||||
|
||||
Model::~Model() {}
|
||||
|
||||
Model* Model::createModelFromFile(Device &device, const std::string &filepath) {
|
||||
Model* Model::createModelFromFile(const std::string &filepath) {
|
||||
Builder builder{};
|
||||
builder.loadModel(filepath);
|
||||
return new Model(device, builder);
|
||||
return new Model(builder);
|
||||
}
|
||||
|
||||
void Model::createVertexBuffers(const std::vector<unsigned char> &vertexData, uint32_t vertexSize) {
|
||||
|
|
|
@ -34,13 +34,13 @@ class Model {
|
|||
void loadModel(const std::string &filepath);
|
||||
};
|
||||
|
||||
Model(Device &device, const Model::Builder &builder);
|
||||
Model(const Model::Builder &builder);
|
||||
~Model();
|
||||
|
||||
Model(const Model &) = delete;
|
||||
Model operator=(const Model &) = delete;
|
||||
|
||||
static Model* createModelFromFile(Device &device, const std::string &filepath);
|
||||
static Model* createModelFromFile(const std::string &filepath);
|
||||
|
||||
void bind(VkCommandBuffer commandBuffer);
|
||||
void draw(VkCommandBuffer commandBuffer);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "xe_device.hpp"
|
||||
#include "xe_game_object.hpp"
|
||||
#include "xe_swap_chain.hpp"
|
||||
#include "xe_descriptors.hpp"
|
||||
#include "xe_window.hpp"
|
||||
|
|
|
@ -16,14 +16,14 @@ Chunk::Chunk(int32_t gridX, int32_t gridZ, uint32_t world_seed)
|
|||
}
|
||||
|
||||
Chunk::~Chunk() {
|
||||
if(chunkMesh != nullptr)
|
||||
delete chunkMesh;
|
||||
if(worker.joinable())
|
||||
worker.join();
|
||||
if(chunkMesh != nullptr)
|
||||
delete chunkMesh;
|
||||
}
|
||||
|
||||
//
|
||||
// CHUNK CREATION AND DELETION
|
||||
// CHUNK CREATION, DELETION, AND RETREVAL
|
||||
//
|
||||
|
||||
static std::map<std::pair<int32_t, int32_t>, Chunk*> chunks{};
|
||||
|
@ -38,10 +38,17 @@ Chunk* Chunk::getChunk(int32_t gridX, int32_t gridZ) {
|
|||
if(chunks.count({gridX, gridZ})) {
|
||||
return chunks[{gridX, gridZ}];
|
||||
} else {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Chunk::deleteChunk(int32_t gridX, int32_t gridZ) {
|
||||
Chunk* chunk = getChunk(gridX, gridZ);
|
||||
if(chunk == nullptr) return; // Chunk does not exist or is already deleted
|
||||
delete chunk;
|
||||
chunks.erase({gridX, gridZ});
|
||||
}
|
||||
|
||||
//
|
||||
// CHUNK TEXTURE AND BLOCK LOADING
|
||||
//
|
||||
|
@ -51,7 +58,7 @@ static std::map<std::string, uint32_t> texturesIds{};
|
|||
static std::vector<xe::Image*> textures{};
|
||||
|
||||
void loadTexture(const std::string& filePath) {
|
||||
xe::Image* image = xe::Engine::getInstance()->loadImageFromFile(filePath, false);
|
||||
xe::Image* image = new xe::Image(filePath, false);
|
||||
texturesIds[filePath] = static_cast<uint32_t>(textures.size());
|
||||
textures.push_back(image);
|
||||
}
|
||||
|
@ -88,12 +95,15 @@ void Chunk::unload() {
|
|||
//
|
||||
|
||||
void Chunk::createMeshAsync(Chunk* c) {
|
||||
if(c == nullptr) return;
|
||||
if(c->working) return;
|
||||
if(c->worker.joinable())
|
||||
c->worker.join();
|
||||
c->worker = std::thread(createMesh, c);
|
||||
}
|
||||
|
||||
void Chunk::createMesh(Chunk* c) {
|
||||
c->working = true;
|
||||
if(c == nullptr) return;
|
||||
c->vertexData.data.clear();
|
||||
for(int32_t x=0;x<16;x++) {
|
||||
for(int32_t y=0; y<256; y++) {
|
||||
|
@ -152,7 +162,7 @@ xe::Model* Chunk::getMesh() {
|
|||
xe::Model::Builder builder{};
|
||||
builder.vertexData = vertexData;
|
||||
builder.vertexSize = 36;
|
||||
chunkMesh = new xe::Model(xe::Engine::getInstance()->getDevice(), builder);
|
||||
chunkMesh = new xe::Model(builder);
|
||||
reloadRequired = false;
|
||||
}
|
||||
return chunkMesh;
|
||||
|
|
|
@ -39,6 +39,7 @@ class Chunk {
|
|||
|
||||
static Chunk* newChunk(int32_t gridX, int32_t gridZ, uint32_t world_seed);
|
||||
static Chunk* getChunk(int32_t gridX, int32_t gridZ);
|
||||
static void deleteChunk(int32_t gridX, int32_t gridZ);
|
||||
|
||||
static void createMesh(Chunk* c);
|
||||
static void createMeshAsync(Chunk* c);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "first_app.hpp"
|
||||
#include "chunk.hpp"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -11,15 +10,11 @@ void FirstApp::run() {
|
|||
|
||||
Chunk::load();
|
||||
|
||||
for(int32_t x = 0; x < 10; x++) {
|
||||
for(int32_t z = 0; z < 10; z++) {
|
||||
Chunk* chunk = Chunk::newChunk(x, z, 53463);
|
||||
Chunk::createMeshAsync(chunk);
|
||||
auto chunkObject = xe::GameObject::createGameObject();
|
||||
chunkObject.transform.translation = {16.f*x, 0.f, 16.f*z};
|
||||
gameObjects.push_back(std::move(chunkObject));
|
||||
}
|
||||
}
|
||||
auto viewerObject = xe::GameObject::createGameObject();
|
||||
viewerObject.transform.translation = {0.f, 10.f, 0.f};
|
||||
viewerObject.transform.rotation.y = glm::radians(45.f);
|
||||
|
||||
createGameObjects(viewerObject);
|
||||
|
||||
SimpleRenderer renderer{xeEngine, Chunk::getTextures()};
|
||||
|
||||
|
@ -27,9 +22,6 @@ void FirstApp::run() {
|
|||
sound.setLooping(true);
|
||||
sound.play();
|
||||
|
||||
auto viewerObject = xe::GameObject::createGameObject();
|
||||
viewerObject.transform.translation = {0.f, 10.f, 0.f};
|
||||
viewerObject.transform.rotation.y = glm::radians(45.f);
|
||||
KeyboardMovementController cameraController{xeEngine.getInput(), viewerObject};
|
||||
|
||||
while (xeEngine.poll()) {
|
||||
|
@ -40,10 +32,12 @@ void FirstApp::run() {
|
|||
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
|
||||
|
||||
if(xeEngine.beginFrame()) {
|
||||
renderer.render(gameObjects, xeEngine.getCamera());
|
||||
renderer.render(loadedChunks, xeEngine.getCamera());
|
||||
xeEngine.endFrame();
|
||||
}
|
||||
|
||||
reloadLoadedChunks(viewerObject);
|
||||
|
||||
}
|
||||
|
||||
xeEngine.close();
|
||||
|
@ -52,4 +46,46 @@ void FirstApp::run() {
|
|||
|
||||
}
|
||||
|
||||
void FirstApp::createGameObjects(xe::GameObject& viewer) {
|
||||
int width = 2*RENDER_DISTANCE+1;
|
||||
loadedChunks.clear();
|
||||
for(int32_t x = 0; x < width; x++) {
|
||||
for(int32_t z = 0; z < width; z++) {
|
||||
auto gameObject = xe::GameObject::createGameObject();
|
||||
gameObject.transform.translation = glm::vec3(0.f);
|
||||
loadedChunks.push_back(std::move(gameObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FirstApp::reloadLoadedChunks(xe::GameObject& viewer) {
|
||||
viewX = static_cast<int>(floor(viewer.transform.translation.x / 16.f));
|
||||
viewZ = static_cast<int>(floor(viewer.transform.translation.z / 16.f));
|
||||
int width = 2*RENDER_DISTANCE+1;
|
||||
int minX = viewX - RENDER_DISTANCE;
|
||||
int minZ = viewZ - RENDER_DISTANCE;
|
||||
int maxX = viewX + RENDER_DISTANCE;
|
||||
int maxZ = viewZ + RENDER_DISTANCE;
|
||||
for(int32_t x = 0; x < width; x++) {
|
||||
for(int32_t z = 0; z < width; z++) {
|
||||
auto& gameObject = loadedChunks[x + z * width];
|
||||
int gridX = static_cast<int>(floor(gameObject.transform.translation.x / 16.f));
|
||||
int gridZ = static_cast<int>(floor(gameObject.transform.translation.z / 16.f));
|
||||
int newGridX = minX + x;
|
||||
int newGridZ = minZ + z;
|
||||
if(gridX < minX || gridZ < minZ || gridX > maxX || gridZ > maxZ)
|
||||
Chunk::deleteChunk(gridX, gridZ);
|
||||
Chunk* chunk = Chunk::getChunk(newGridX, newGridZ);
|
||||
if(chunk == nullptr) {
|
||||
chunk = Chunk::newChunk(newGridX, newGridZ, 12345);
|
||||
Chunk::createMeshAsync(chunk);
|
||||
Chunk::createMeshAsync(Chunk::getChunk(newGridX-1, newGridZ));
|
||||
Chunk::createMeshAsync(Chunk::getChunk(newGridX, newGridZ+1));
|
||||
}
|
||||
gameObject.model = chunk->getMesh();
|
||||
gameObject.transform.translation = glm::vec3(newGridX * 16.f, 0, newGridZ * 16.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "keyboard_movement_controller.hpp"
|
||||
#include "simple_renderer.hpp"
|
||||
#include "chunk.hpp"
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
|
@ -31,9 +32,15 @@ class FirstApp {
|
|||
|
||||
static constexpr int WIDTH = 800;
|
||||
static constexpr int HEIGHT = 600;
|
||||
static constexpr int RENDER_DISTANCE = 10;
|
||||
|
||||
void createGameObjects(xe::GameObject& viewer);
|
||||
void reloadLoadedChunks(xe::GameObject& viewer);
|
||||
|
||||
|
||||
int viewX, viewZ;
|
||||
|
||||
xe::Engine xeEngine;
|
||||
|
||||
std::vector<xe::GameObject> gameObjects;
|
||||
std::vector<xe::GameObject> loadedChunks;
|
||||
};
|
||||
}
|
|
@ -29,10 +29,6 @@ void SimpleRenderer::render(std::vector<xe::GameObject> &gameObjects, xe::Camera
|
|||
PushConstant pc{};
|
||||
pc.modelMatrix = obj.transform.mat4();
|
||||
pc.normalMatrix = obj.transform.normalMatrix();
|
||||
|
||||
Chunk* chunk = Chunk::getChunk(obj.transform.translation.x/16.f, obj.transform.translation.z/16.f);
|
||||
obj.model = chunk->getMesh();
|
||||
|
||||
xeRenderSystem->loadPushConstant(&pc);
|
||||
xeRenderSystem->render(obj);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue