initial update/mesh/render thread communication refactor
Quirks to iron out: - Some stuff is rendered wrong/not rendered (chunks missing) - Still no way to delete stuff from ChunksToRenderfix-multithread
parent
a05d019c69
commit
ca44c0f284
|
@ -25,14 +25,11 @@ namespace Chunk
|
||||||
|
|
||||||
constexpr uint16_t CHUNK_STATE_GENERATED = 1;
|
constexpr uint16_t CHUNK_STATE_GENERATED = 1;
|
||||||
constexpr uint16_t CHUNK_STATE_MESHED = 2;
|
constexpr uint16_t CHUNK_STATE_MESHED = 2;
|
||||||
constexpr uint16_t CHUNK_STATE_MESH_LOADED = 4;
|
|
||||||
constexpr uint16_t CHUNK_STATE_LOADED = 8;
|
|
||||||
constexpr uint16_t CHUNK_STATE_OUTOFVISION = 16;
|
constexpr uint16_t CHUNK_STATE_OUTOFVISION = 16;
|
||||||
constexpr uint16_t CHUNK_STATE_UNLOADED = 32;
|
constexpr uint16_t CHUNK_STATE_UNLOADED = 32;
|
||||||
constexpr uint16_t CHUNK_STATE_EMPTY = 64;
|
constexpr uint16_t CHUNK_STATE_EMPTY = 64;
|
||||||
constexpr uint16_t CHUNK_STATE_IN_GENERATION_QUEUE = 128;
|
constexpr uint16_t CHUNK_STATE_IN_GENERATION_QUEUE = 128;
|
||||||
constexpr uint16_t CHUNK_STATE_IN_MESHING_QUEUE = 256;
|
constexpr uint16_t CHUNK_STATE_IN_MESHING_QUEUE = 256;
|
||||||
constexpr uint16_t CHUNK_STATE_IN_RENDERING_QUEUE = 512;
|
|
||||||
|
|
||||||
int coord3DTo1D(int x, int y, int z);
|
int coord3DTo1D(int x, int y, int z);
|
||||||
|
|
||||||
|
@ -61,12 +58,14 @@ namespace Chunk
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLuint VAO{0}, VBO{0}, extentsBuffer{0}, texinfoBuffer{0}, numVertices{0};
|
GLuint VAO{0}, VBO{0}, extentsBuffer{0}, texinfoBuffer{0}, numVertices{0};
|
||||||
|
int32_t getIndex(){ return index; }
|
||||||
std::atomic<float> unload_timer{0};
|
std::atomic<float> unload_timer{0};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 position{};
|
glm::vec3 position{};
|
||||||
IntervalMap<Block> blocks{};
|
IntervalMap<Block> blocks{};
|
||||||
|
|
||||||
|
int32_t index;
|
||||||
std::atomic_uint16_t state{0};
|
std::atomic_uint16_t state{0};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
namespace chunkmanager
|
namespace chunkmanager
|
||||||
{
|
{
|
||||||
typedef oneapi::tbb::concurrent_hash_map<uint32_t, Chunk::Chunk*> ChunkTable;
|
typedef oneapi::tbb::concurrent_hash_map<int32_t, Chunk::Chunk*> ChunkTable;
|
||||||
typedef oneapi::tbb::concurrent_queue<int> IntQueue;
|
typedef oneapi::tbb::concurrent_queue<int> IntQueue;
|
||||||
|
|
||||||
//typedef std::unordered_map<int32_t, Chunk::Chunk*> ChunkTable;
|
//typedef std::unordered_map<int32_t, Chunk::Chunk*> ChunkTable;
|
||||||
|
@ -37,6 +37,8 @@ namespace chunkmanager
|
||||||
void init();
|
void init();
|
||||||
void blockpick(bool place);
|
void blockpick(bool place);
|
||||||
int32_t calculateIndex(int16_t i, int16_t j, int16_t k);
|
int32_t calculateIndex(int16_t i, int16_t j, int16_t k);
|
||||||
|
int32_t calculateIndex(Chunk::Chunk* c);
|
||||||
|
int32_t calculateIndex(glm::vec3 position);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef CHUNK_MESH_DATA_H
|
||||||
|
#define CHUNK_MESH_DATA_H
|
||||||
|
|
||||||
|
enum class ChunkMeshDataType{
|
||||||
|
MESH_UPDATE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ChunkMeshData{
|
||||||
|
int32_t index;
|
||||||
|
glm::vec3 position;
|
||||||
|
int num_vertices = 0;
|
||||||
|
|
||||||
|
std::vector<GLfloat> vertices;
|
||||||
|
std::vector<GLfloat> extents;
|
||||||
|
std::vector<GLfloat> texinfo;
|
||||||
|
|
||||||
|
ChunkMeshDataType message_type;
|
||||||
|
|
||||||
|
void clear(){
|
||||||
|
vertices.clear();
|
||||||
|
texinfo.clear();
|
||||||
|
extents.clear();
|
||||||
|
index = 0;
|
||||||
|
position = glm::vec3(0);
|
||||||
|
num_vertices = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}ChunkMeshData;
|
||||||
|
typedef oneapi::tbb::concurrent_queue<ChunkMeshData*> ChunkMeshDataQueue;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,28 +5,19 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <oneapi/tbb/concurrent_queue.h>
|
#include <oneapi/tbb/concurrent_queue.h>
|
||||||
|
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
|
#include "chunkmeshdata.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
#include "shader.hpp"
|
#include "shader.hpp"
|
||||||
|
|
||||||
namespace chunkmesher{
|
namespace chunkmesher{
|
||||||
struct MeshData{
|
ChunkMeshDataQueue& getMeshDataQueue();
|
||||||
Chunk::Chunk* chunk;
|
void init();
|
||||||
GLuint numVertices{0};
|
|
||||||
|
|
||||||
std::vector<GLfloat> vertices;
|
|
||||||
std::vector<GLfloat> extents;
|
|
||||||
std::vector<GLfloat> texinfo;
|
|
||||||
};
|
|
||||||
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue();
|
|
||||||
|
|
||||||
void mesh(Chunk::Chunk* chunk);
|
void mesh(Chunk::Chunk* chunk);
|
||||||
void sendtogpu(MeshData* mesh_data);
|
|
||||||
void quad(MeshData* mesh_data, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
|
|
||||||
glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,35 @@
|
||||||
#ifndef RENDERER_H
|
#ifndef RENDERER_H
|
||||||
#define RENDERER_H
|
#define RENDERER_H
|
||||||
|
|
||||||
#include <oneapi/tbb/concurrent_unordered_set.h>
|
#include <glm/glm.hpp>
|
||||||
#include <oneapi/tbb/concurrent_queue.h>
|
|
||||||
|
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "chunkmesher.hpp"
|
#include "chunkmesher.hpp"
|
||||||
|
#include "chunkmeshdata.hpp"
|
||||||
#include "shader.hpp"
|
#include "shader.hpp"
|
||||||
|
|
||||||
namespace renderer{
|
namespace renderer{
|
||||||
//typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
|
typedef struct RenderInfo {
|
||||||
typedef oneapi::tbb::concurrent_queue<Chunk::Chunk*> RenderQueue;
|
int32_t index;
|
||||||
|
int num_vertices;
|
||||||
|
glm::vec3 position;
|
||||||
|
bool buffers_allocated=false;
|
||||||
|
|
||||||
|
GLuint VAO, VBO, extentsBuffer, texinfoBuffer;
|
||||||
|
|
||||||
|
void allocateBuffers(){
|
||||||
|
// Allocate buffers
|
||||||
|
glGenVertexArrays(1, &VAO);
|
||||||
|
glGenBuffers(1, &VBO);
|
||||||
|
glGenBuffers(1, &extentsBuffer);
|
||||||
|
glGenBuffers(1, &texinfoBuffer);
|
||||||
|
|
||||||
|
buffers_allocated=true;
|
||||||
|
}
|
||||||
|
} RenderInfo;
|
||||||
|
|
||||||
void init(GLFWwindow* window);
|
void init(GLFWwindow* window);
|
||||||
|
void send_chunk_to_gpu(ChunkMeshData* mesh_data, RenderInfo* render_info);
|
||||||
void render();
|
void render();
|
||||||
void resize_framebuffer(int width, int height);
|
void resize_framebuffer(int width, int height);
|
||||||
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
|
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
|
||||||
|
@ -21,8 +38,7 @@ namespace renderer{
|
||||||
void saveScreenshot(bool forceFullHD=false);
|
void saveScreenshot(bool forceFullHD=false);
|
||||||
|
|
||||||
Shader* getRenderShader();
|
Shader* getRenderShader();
|
||||||
RenderQueue& getChunksToRender();
|
ChunkMeshDataQueue& getMeshDataQueue();
|
||||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,21 +20,11 @@ namespace Chunk
|
||||||
this->position = pos;
|
this->position = pos;
|
||||||
this->setState(CHUNK_STATE_EMPTY, true);
|
this->setState(CHUNK_STATE_EMPTY, true);
|
||||||
this->setBlocks(0, CHUNK_MAX_INDEX, Block::AIR);
|
this->setBlocks(0, CHUNK_MAX_INDEX, Block::AIR);
|
||||||
}
|
|
||||||
|
|
||||||
void Chunk::createBuffers(){
|
int16_t i = static_cast<int16_t>(pos.x);
|
||||||
glGenVertexArrays(1, &(this->VAO));
|
int16_t j = static_cast<int16_t>(pos.y);
|
||||||
glGenBuffers(1, &(this->VBO));
|
int16_t k = static_cast<int16_t>(pos.z);
|
||||||
glGenBuffers(1, &(this->extentsBuffer));
|
index = i | (j << 10) | (k << 20);
|
||||||
glGenBuffers(1, &(this->texinfoBuffer));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chunk::deleteBuffers(){
|
|
||||||
glDeleteBuffers(1, &(this->VBO));
|
|
||||||
glDeleteBuffers(1, &(this->extentsBuffer));
|
|
||||||
glDeleteBuffers(1, &(this->texinfoBuffer));
|
|
||||||
glDeleteVertexArrays(1, &(this->VAO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Block Chunk::getBlock(int x, int y, int z)
|
Block Chunk::getBlock(int x, int y, int z)
|
||||||
|
|
|
@ -59,10 +59,6 @@ namespace chunkmanager
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also init mesh data queue
|
|
||||||
for(int i = 0; i < 10; i++)
|
|
||||||
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
|
|
||||||
|
|
||||||
should_run = true;
|
should_run = true;
|
||||||
update_thread = std::thread(update);
|
update_thread = std::thread(update);
|
||||||
gen_thread = std::thread(generate);
|
gen_thread = std::thread(generate);
|
||||||
|
@ -80,7 +76,7 @@ namespace chunkmanager
|
||||||
entry.first->setState(Chunk::CHUNK_STATE_IN_GENERATION_QUEUE, false);
|
entry.first->setState(Chunk::CHUNK_STATE_IN_GENERATION_QUEUE, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunks_to_generate_queue.clear();
|
//chunks_to_generate_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method for chunk meshing thread(s)
|
// Method for chunk meshing thread(s)
|
||||||
|
@ -93,7 +89,7 @@ namespace chunkmanager
|
||||||
chunk->setState(Chunk::CHUNK_STATE_IN_MESHING_QUEUE, false);
|
chunk->setState(Chunk::CHUNK_STATE_IN_MESHING_QUEUE, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunks_to_mesh_queue.clear();
|
//chunks_to_mesh_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(){
|
void update(){
|
||||||
|
@ -177,10 +173,6 @@ namespace chunkmanager
|
||||||
}else{
|
}else{
|
||||||
mesh++;
|
mesh++;
|
||||||
// If generated & meshed, render
|
// If generated & meshed, render
|
||||||
/*if(!c->getState(Chunk::CHUNK_STATE_IN_RENDERING_QUEUE)){
|
|
||||||
renderer::getChunksToRender().push(c);
|
|
||||||
c->setState(Chunk::CHUNK_STATE_IN_RENDERING_QUEUE, true);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +181,7 @@ namespace chunkmanager
|
||||||
if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
||||||
// If enough time has passed, set to be deleted
|
// If enough time has passed, set to be deleted
|
||||||
if(c->isFree() && glfwGetTime() - c->unload_timer >= UNLOAD_TIMEOUT){
|
if(c->isFree() && glfwGetTime() - c->unload_timer >= UNLOAD_TIMEOUT){
|
||||||
chunks_todelete.push(calculateIndex(x,y,z));
|
chunks_todelete.push(c->getIndex());
|
||||||
unload++;
|
unload++;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
@ -230,6 +222,13 @@ namespace chunkmanager
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1023). There's actually two spare bits
|
// uint32_t is fine, since i'm limiting the coordinate to only use up to ten bits (1023). There's actually two spare bits
|
||||||
|
int32_t calculateIndex(Chunk::Chunk* c){
|
||||||
|
return calculateIndex(c->getPosition());
|
||||||
|
}
|
||||||
|
int32_t calculateIndex(glm::vec3 position){
|
||||||
|
return calculateIndex(static_cast<int16_t>(position.x), static_cast<int16_t>(position.y),
|
||||||
|
static_cast<int16_t>(position.z));
|
||||||
|
}
|
||||||
int32_t calculateIndex(int16_t i, int16_t j, int16_t k){
|
int32_t calculateIndex(int16_t i, int16_t j, int16_t k){
|
||||||
return i | (j << 10) | (k << 20);
|
return i | (j << 10) | (k << 20);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,17 @@
|
||||||
|
|
||||||
namespace chunkmesher{
|
namespace chunkmesher{
|
||||||
|
|
||||||
oneapi::tbb::concurrent_queue<MeshData*> MeshDataQueue;
|
ChunkMeshDataQueue MeshDataQueue;
|
||||||
|
ChunkMeshDataQueue& getMeshDataQueue(){ return MeshDataQueue; }
|
||||||
|
|
||||||
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
void init(){
|
||||||
|
for(int i = 0; i < 10; i++)
|
||||||
|
MeshDataQueue.push(new ChunkMeshData{});
|
||||||
|
}
|
||||||
|
|
||||||
void mesh(Chunk::Chunk* chunk)
|
void mesh(Chunk::Chunk* chunk)
|
||||||
{
|
{
|
||||||
MeshData* mesh_data;
|
ChunkMeshData* mesh_data;
|
||||||
if(!MeshDataQueue.try_pop(mesh_data)) return;
|
if(!MeshDataQueue.try_pop(mesh_data)) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -38,28 +42,13 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Cleanup previous data
|
// Cleanup previous data
|
||||||
mesh_data->numVertices = 0;
|
mesh_data->clear();
|
||||||
mesh_data->chunk = chunk;
|
mesh_data->message_type = ChunkMeshDataType::MESH_UPDATE;
|
||||||
mesh_data->vertices.clear();
|
mesh_data->index = chunk->getIndex();
|
||||||
mesh_data->extents.clear();
|
mesh_data->position = chunk->getPosition();
|
||||||
mesh_data->texinfo.clear();
|
|
||||||
|
|
||||||
// Abort if chunk is empty
|
std::unique_ptr<Block[]> blocks;
|
||||||
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)){
|
|
||||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
|
||||||
renderer::getMeshDataQueue().push(mesh_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert tree to array since it is easier to work with it
|
|
||||||
int length{0};
|
int length{0};
|
||||||
std::unique_ptr<Block[]> blocks = chunk->getBlocksArray(&length);
|
|
||||||
if(length == 0) {
|
|
||||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
|
||||||
renderer::getMeshDataQueue().push(mesh_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int k, l, u, v, w, h, n, j, i;
|
int k, l, u, v, w, h, n, j, i;
|
||||||
int x[]{0, 0, 0};
|
int x[]{0, 0, 0};
|
||||||
int q[]{0, 0, 0};
|
int q[]{0, 0, 0};
|
||||||
|
@ -67,6 +56,14 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
int dv[]{0, 0, 0};
|
int dv[]{0, 0, 0};
|
||||||
|
|
||||||
std::array<Block, CHUNK_SIZE * CHUNK_SIZE> mask;
|
std::array<Block, CHUNK_SIZE * CHUNK_SIZE> mask;
|
||||||
|
|
||||||
|
// Abort if chunk is empty
|
||||||
|
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)) goto end;
|
||||||
|
|
||||||
|
// convert tree to array since it is easier to work with it
|
||||||
|
blocks = chunk->getBlocksArray(&length);
|
||||||
|
if(length == 0) goto end;
|
||||||
|
|
||||||
for (bool backFace = true, b = false; b != backFace; backFace = backFace && b, b = !b)
|
for (bool backFace = true, b = false; b != backFace; backFace = backFace && b, b = !b)
|
||||||
{
|
{
|
||||||
// iterate over 3 dimensions
|
// iterate over 3 dimensions
|
||||||
|
@ -188,14 +185,15 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
mesh_data->vertices.push_back(x[1]); //bottomLeft.y
|
mesh_data->vertices.push_back(x[1]); //bottomLeft.y
|
||||||
mesh_data->vertices.push_back(x[2]); //bottomLeft.z
|
mesh_data->vertices.push_back(x[2]); //bottomLeft.z
|
||||||
|
|
||||||
// extents, use normals for now
|
// extents
|
||||||
mesh_data->extents.push_back(du[0] + dv[0]);
|
mesh_data->extents.push_back(du[0] + dv[0]);
|
||||||
mesh_data->extents.push_back(du[1] + dv[1]);
|
mesh_data->extents.push_back(du[1] + dv[1]);
|
||||||
mesh_data->extents.push_back(du[2] + dv[2]);
|
mesh_data->extents.push_back(du[2] + dv[2]);
|
||||||
|
|
||||||
|
// texture info (block type, backFace)
|
||||||
mesh_data->texinfo.push_back(backFace ? 0.0 : 1.0);
|
mesh_data->texinfo.push_back(backFace ? 0.0 : 1.0);
|
||||||
mesh_data->texinfo.push_back((int)(mask[n]) - 2);
|
mesh_data->texinfo.push_back((int)(mask[n]) - 2);
|
||||||
mesh_data->numVertices++;
|
mesh_data->num_vertices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (l = 0; l < h; ++l)
|
for (l = 0; l < h; ++l)
|
||||||
|
@ -224,49 +222,8 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||||
renderer::getMeshDataQueue().push(mesh_data);
|
renderer::getMeshDataQueue().push(mesh_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendtogpu(MeshData* mesh_data)
|
|
||||||
{
|
|
||||||
if (mesh_data->numVertices > 0)
|
|
||||||
{
|
|
||||||
if(mesh_data->chunk->VAO == 0) mesh_data->chunk->createBuffers();
|
|
||||||
|
|
||||||
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
|
||||||
glBindVertexArray(mesh_data->chunk->VAO);
|
|
||||||
|
|
||||||
// position attribute
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->VBO);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->vertices.size() * sizeof(GLfloat), &(mesh_data->vertices[0]), GL_STATIC_DRAW);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
// normal attribute
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->extentsBuffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->extents.size() * sizeof(GLfloat), &(mesh_data->extents[0]), GL_STATIC_DRAW);
|
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(0));
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
|
|
||||||
// texcoords attribute
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->texinfoBuffer);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, mesh_data->texinfo.size() * sizeof(GLfloat), &(mesh_data->texinfo[0]), GL_STATIC_DRAW);
|
|
||||||
glEnableVertexAttribArray(2);
|
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
// save the number of indices of the mesh, it is needed later for drawing
|
|
||||||
mesh_data->chunk->numVertices = (GLuint)(mesh_data->numVertices);
|
|
||||||
|
|
||||||
// once data has been sent to the GPU, it can be cleared from system RAM
|
|
||||||
mesh_data->vertices.clear();
|
|
||||||
mesh_data->extents.clear();
|
|
||||||
mesh_data->texinfo.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark the chunk mesh has loaded on GPU
|
|
||||||
mesh_data->chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,8 +70,9 @@ int main()
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceFilling::initLUT();
|
SpaceFilling::initLUT();
|
||||||
chunkmanager::init();
|
|
||||||
debug::window::init(window);
|
debug::window::init(window);
|
||||||
|
chunkmanager::init();
|
||||||
|
chunkmesher::init();
|
||||||
renderer::init(window);
|
renderer::init(window);
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window))
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#include <glm/ext.hpp>
|
#include <glm/ext.hpp>
|
||||||
#include <glm/gtx/string_cast.hpp>
|
#include <glm/gtx/string_cast.hpp>
|
||||||
|
|
||||||
#include <oneapi/tbb/concurrent_vector.h>
|
#include <oneapi/tbb/concurrent_hash_map.h>
|
||||||
#include <oneapi/tbb/concurrent_queue.h>
|
|
||||||
|
|
||||||
#include "chunkmanager.hpp"
|
#include "chunkmanager.hpp"
|
||||||
#include "chunkmesher.hpp"
|
#include "chunkmesher.hpp"
|
||||||
|
@ -15,22 +14,23 @@
|
||||||
#include "stb_image_write.h"
|
#include "stb_image_write.h"
|
||||||
|
|
||||||
namespace renderer{
|
namespace renderer{
|
||||||
RenderQueue chunks_torender;
|
typedef oneapi::tbb::concurrent_hash_map<int32_t, RenderInfo*> RenderTable;
|
||||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*> MeshDataQueue;
|
|
||||||
|
RenderTable ChunksToRender;
|
||||||
|
ChunkMeshDataQueue MeshDataQueue;
|
||||||
|
|
||||||
Shader* theShader, *quadShader;
|
Shader* theShader, *quadShader;
|
||||||
GLuint chunkTexture;
|
GLuint chunkTexture;
|
||||||
|
|
||||||
Shader* getRenderShader() { return theShader; }
|
|
||||||
RenderQueue& getChunksToRender(){ return chunks_torender; }
|
|
||||||
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
|
||||||
|
|
||||||
GLuint renderTexFrameBuffer, renderTex, renderTexDepthBuffer, quadVAO, quadVBO;
|
GLuint renderTexFrameBuffer, renderTex, renderTexDepthBuffer, quadVAO, quadVBO;
|
||||||
int screenWidth, screenHeight;
|
int screenWidth, screenHeight;
|
||||||
|
|
||||||
int crosshair_type{0};
|
int crosshair_type{0};
|
||||||
bool wireframe{false};
|
bool wireframe{false};
|
||||||
|
|
||||||
|
Shader* getRenderShader() { return theShader; }
|
||||||
|
ChunkMeshDataQueue& getMeshDataQueue(){ return MeshDataQueue; }
|
||||||
|
|
||||||
void init(GLFWwindow* window){
|
void init(GLFWwindow* window){
|
||||||
// Setup rendering
|
// Setup rendering
|
||||||
// We will render the image to a texture, then display the texture on a quad that fills the
|
// We will render the image to a texture, then display the texture on a quad that fills the
|
||||||
|
@ -140,26 +140,49 @@ namespace renderer{
|
||||||
theShader->use();
|
theShader->use();
|
||||||
theShader->setVec3("viewPos", cameraPos);
|
theShader->setVec3("viewPos", cameraPos);
|
||||||
|
|
||||||
chunkmesher::MeshData* m;
|
// TODO: works but some stuff is rendered wrong (trees floating or inside the terrain,
|
||||||
|
// missing or malformed chunks)
|
||||||
|
ChunkMeshData* m;
|
||||||
while(MeshDataQueue.try_pop(m)){
|
while(MeshDataQueue.try_pop(m)){
|
||||||
chunkmesher::sendtogpu(m);
|
RenderTable::accessor a;
|
||||||
|
RenderInfo* render_info;
|
||||||
|
|
||||||
|
if(ChunksToRender.find(a, m->index)){
|
||||||
|
render_info = a->second;
|
||||||
|
render_info->position = m->position;
|
||||||
|
render_info->num_vertices = m->num_vertices;
|
||||||
|
std::cout << "index collision on " << render_info->index << std::endl;
|
||||||
|
}else{
|
||||||
|
render_info = new RenderInfo();
|
||||||
|
render_info->index = m->index;
|
||||||
|
render_info->position = m->position;
|
||||||
|
render_info->num_vertices = m->num_vertices;
|
||||||
|
|
||||||
|
ChunksToRender.emplace(a, std::make_pair(render_info->index, render_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
send_chunk_to_gpu(m, render_info);
|
||||||
chunkmesher::getMeshDataQueue().push(m);
|
chunkmesher::getMeshDataQueue().push(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk::Chunk* c;
|
// TODO: implement removal of chunks from rendering
|
||||||
while(chunks_torender.try_pop(c)){
|
std::cout << "chunks to render: " << ChunksToRender.size();
|
||||||
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) goto end;
|
|
||||||
|
|
||||||
|
// Render the chunks
|
||||||
|
// parallel_for cannot be used since all the rendering needs to happen in a single thread
|
||||||
|
for(RenderTable::iterator i = ChunksToRender.begin(); i != ChunksToRender.end(); i++){
|
||||||
|
RenderInfo* render_info = i->second;
|
||||||
|
|
||||||
total++;
|
total++;
|
||||||
|
if(render_info->num_vertices > 0)
|
||||||
if(c->numVertices > 0)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// Increase total vertex count
|
// Increase total vertex count
|
||||||
vertices += c->numVertices;
|
vertices += render_info->num_vertices;
|
||||||
|
|
||||||
// Perform frustum culling and eventually render
|
// Perform frustum culling and eventually render
|
||||||
glm::vec3 chunk = c->getPosition();
|
glm::vec3 chunk = render_info->position;
|
||||||
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
glm::vec4 chunkW = glm::vec4(chunk.x*static_cast<float>(CHUNK_SIZE), chunk.y*static_cast<float>(CHUNK_SIZE), chunk.z*static_cast<float>(CHUNK_SIZE),1.0);
|
||||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
||||||
|
|
||||||
|
@ -185,16 +208,13 @@ namespace renderer{
|
||||||
theShader->setMat4("view", theCamera.getView());
|
theShader->setMat4("view", theCamera.getView());
|
||||||
theShader->setMat4("projection", theCamera.getProjection());
|
theShader->setMat4("projection", theCamera.getProjection());
|
||||||
|
|
||||||
glBindVertexArray(c->VAO);
|
glBindVertexArray(render_info->VAO);
|
||||||
glDrawArrays(GL_POINTS, 0, c->numVertices);
|
glDrawArrays(GL_POINTS, 0, render_info->num_vertices);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
toGpu++;
|
toGpu++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
|
||||||
c->setState(Chunk::CHUNK_STATE_IN_RENDERING_QUEUE, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug::window::set_parameter("render_chunks_total", total);
|
debug::window::set_parameter("render_chunks_total", total);
|
||||||
|
@ -223,6 +243,39 @@ end:
|
||||||
debug::window::render();
|
debug::window::render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_chunk_to_gpu(ChunkMeshData* mesh_data, RenderInfo* render_info)
|
||||||
|
{
|
||||||
|
if (render_info->num_vertices > 0)
|
||||||
|
{
|
||||||
|
if(!render_info->buffers_allocated) render_info->allocateBuffers();
|
||||||
|
|
||||||
|
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||||
|
glBindVertexArray(render_info->VAO);
|
||||||
|
|
||||||
|
// TODO: change GL_STATIC_DRAW to the one that means "few redraws and further in between"
|
||||||
|
|
||||||
|
// position attribute
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, render_info->VBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, mesh_data->vertices.size() * sizeof(GLfloat), &(mesh_data->vertices[0]), GL_STATIC_DRAW);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
// normal attribute
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, render_info->extentsBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, mesh_data->extents.size() * sizeof(GLfloat), &(mesh_data->extents[0]), GL_STATIC_DRAW);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(0));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
// texcoords attribute
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, render_info->texinfoBuffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, mesh_data->texinfo.size() * sizeof(GLfloat), &(mesh_data->texinfo[0]), GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void framebuffer_size_callback(GLFWwindow *window, int width, int height){
|
void framebuffer_size_callback(GLFWwindow *window, int width, int height){
|
||||||
resize_framebuffer(width, height);
|
resize_framebuffer(width, height);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue