commit
802257abe3
|
@ -4,6 +4,7 @@ project(cmake-project-template)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")
|
||||||
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g")
|
||||||
|
|
||||||
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})
|
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <atomic>
|
||||||
|
|
||||||
class Camera
|
class Camera
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ public:
|
||||||
view = glm::mat4(1.0f);
|
view = glm::mat4(1.0f);
|
||||||
|
|
||||||
// This matrix needs to be also updated in viewPortCallback whenever it is changed
|
// This matrix needs to be also updated in viewPortCallback whenever it is changed
|
||||||
projection = glm::perspective(glm::radians(90.0f), 800.0f / 600.0f, 0.1f, 200.0f);
|
projection = glm::perspective(glm::radians(90.0f), 800.0f / 600.0f, 0.1f, 1200.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(GLFWwindow *window, float deltaTime)
|
void update(GLFWwindow *window, float deltaTime)
|
||||||
|
@ -38,6 +38,9 @@ public:
|
||||||
if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS)
|
if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS)
|
||||||
this->cameraPos -= cameraSpeed * cameraUp;
|
this->cameraPos -= cameraSpeed * cameraUp;
|
||||||
|
|
||||||
|
posX = cameraPos.x;
|
||||||
|
posY = cameraPos.y;
|
||||||
|
posZ = cameraPos.z;
|
||||||
|
|
||||||
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
|
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
|
||||||
direction.y = sin(glm::radians(pitch));
|
direction.y = sin(glm::radians(pitch));
|
||||||
|
@ -49,7 +52,7 @@ public:
|
||||||
|
|
||||||
void viewPortCallBack(GLFWwindow *window, int width, int height)
|
void viewPortCallBack(GLFWwindow *window, int width, int height)
|
||||||
{
|
{
|
||||||
projection = glm::perspective(glm::radians(80.0f), (float)width / (float)height, 0.1f, 350.0f);
|
projection = glm::perspective(glm::radians(80.0f), (float)width / (float)height, 0.1f, 1200.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mouseCallback(GLFWwindow *window, double xpos, double ypos)
|
void mouseCallback(GLFWwindow *window, double xpos, double ypos)
|
||||||
|
@ -78,6 +81,10 @@ public:
|
||||||
glm::mat4 getView() { return view; }
|
glm::mat4 getView() { return view; }
|
||||||
glm::mat4 getProjection() { return projection; }
|
glm::mat4 getProjection() { return projection; }
|
||||||
|
|
||||||
|
float getAtomicPosX() { return posX; }
|
||||||
|
float getAtomicPosY() { return posY; }
|
||||||
|
float getAtomicPosZ() { return posZ; }
|
||||||
|
|
||||||
// Plane extraction as per Gribb&Hartmann
|
// Plane extraction as per Gribb&Hartmann
|
||||||
// 6 planes, each with 4 components (a,b,c,d)
|
// 6 planes, each with 4 components (a,b,c,d)
|
||||||
void getFrustumPlanes(glm::vec4 planes[6], bool normalize)
|
void getFrustumPlanes(glm::vec4 planes[6], bool normalize)
|
||||||
|
@ -105,7 +112,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 cameraPos = glm::vec3(0.0, 80.0f, 0.0f);
|
glm::vec3 cameraPos = glm::vec3(256.0, 80.0f, 256.0f);
|
||||||
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
|
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
|
||||||
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||||
glm::vec3 direction = glm::vec3(0.0f);
|
glm::vec3 direction = glm::vec3(0.0f);
|
||||||
|
@ -114,6 +121,8 @@ private:
|
||||||
|
|
||||||
float lastX = 400, lastY = 300;
|
float lastX = 400, lastY = 300;
|
||||||
float yaw, pitch;
|
float yaw, pitch;
|
||||||
|
|
||||||
|
std::atomic<float> posX, posY, posZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
#include "intervalmap.hpp"
|
#include "intervalmap.hpp"
|
||||||
#include "shader.hpp"
|
#include "shader.hpp"
|
||||||
|
|
||||||
#define CHUNK_SIZE 16
|
#define CHUNK_SIZE 32
|
||||||
#define CHUNK_VOLUME (CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE)
|
#define CHUNK_VOLUME (CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE)
|
||||||
#define CHUNK_MAX_INDEX (CHUNK_VOLUME - 1)
|
#define CHUNK_MAX_INDEX (CHUNK_VOLUME - 1)
|
||||||
|
|
||||||
|
@ -24,9 +25,11 @@ namespace Chunk
|
||||||
|
|
||||||
constexpr uint8_t CHUNK_STATE_GENERATED = 1;
|
constexpr uint8_t CHUNK_STATE_GENERATED = 1;
|
||||||
constexpr uint8_t CHUNK_STATE_MESHED = 2;
|
constexpr uint8_t CHUNK_STATE_MESHED = 2;
|
||||||
constexpr uint8_t CHUNK_STATE_MESH_LOADED = 3;
|
constexpr uint8_t CHUNK_STATE_MESH_LOADED = 4;
|
||||||
constexpr uint8_t CHUNK_STATE_LOADED = 4;
|
constexpr uint8_t CHUNK_STATE_LOADED = 8;
|
||||||
constexpr uint8_t CHUNK_STATE_EMPTY = 7;
|
constexpr uint8_t CHUNK_STATE_OUTOFVISION = 16;
|
||||||
|
constexpr uint8_t CHUNK_STATE_UNLOADED = 32;
|
||||||
|
constexpr uint8_t CHUNK_STATE_EMPTY = 64;
|
||||||
|
|
||||||
int coord3DTo1D(int x, int y, int z);
|
int coord3DTo1D(int x, int y, int z);
|
||||||
|
|
||||||
|
@ -38,9 +41,12 @@ namespace Chunk
|
||||||
~Chunk();
|
~Chunk();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void createBuffers();
|
||||||
|
void deleteBuffers();
|
||||||
|
|
||||||
glm::vec3 getPosition() { return this->position; }
|
glm::vec3 getPosition() { return this->position; }
|
||||||
std::bitset<8> getTotalState() { return this->state; }
|
uint8_t getTotalState() { return this->state; }
|
||||||
bool getState(uint8_t n) { return this->state.test(n); }
|
bool getState(uint8_t n) { return (this->state & n) == n; }
|
||||||
void setState(uint8_t nstate, bool value);
|
void setState(uint8_t nstate, bool value);
|
||||||
|
|
||||||
void setBlock(Block b, int x, int y, int z);
|
void setBlock(Block b, int x, int y, int z);
|
||||||
|
@ -50,19 +56,14 @@ namespace Chunk
|
||||||
std::unique_ptr<Block[]> getBlocksArray(int* len) { return (this->blocks.toArray(len)); }
|
std::unique_ptr<Block[]> getBlocksArray(int* len) { return (this->blocks.toArray(len)); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, vIndex{0};
|
GLuint VAO{0}, VBO{0}, EBO{0}, colorBuffer{0}, numVertices{0};
|
||||||
|
std::atomic<float> unload_timer{0};
|
||||||
std::mutex mutex_state;
|
|
||||||
|
|
||||||
std::vector<GLfloat> vertices;
|
|
||||||
std::vector<GLfloat> colors;
|
|
||||||
std::vector<GLuint> indices;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 position{};
|
glm::vec3 position{};
|
||||||
IntervalMap<Block> blocks{};
|
IntervalMap<Block> blocks{};
|
||||||
|
|
||||||
std::bitset<8> state{0};
|
std::atomic_uint8_t state{0};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,27 @@
|
||||||
#ifndef CHUNKMANAGER_H
|
#ifndef CHUNKMANAGER_H
|
||||||
#define CHUNKMANAGER_H
|
#define CHUNKMANAGER_H
|
||||||
|
|
||||||
// Second to be passed outside of render distance for a chunk to be destroyed
|
// Seconds to be passed outside of render distance for a chunk to be destroyed
|
||||||
#define UNLOAD_TIMEOUT 10
|
#define UNLOAD_TIMEOUT 10
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <oneapi/tbb/concurrent_queue.h>
|
||||||
|
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
|
||||||
namespace chunkmanager
|
namespace chunkmanager
|
||||||
{
|
{
|
||||||
std::thread initGenThread();
|
std::thread init();
|
||||||
std::thread initMeshThread();
|
|
||||||
void stopGenThread();
|
|
||||||
void stopMeshThread();
|
|
||||||
|
|
||||||
void mesh();
|
|
||||||
void generate();
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void blockpick(bool place);
|
void blockpick(bool place);
|
||||||
uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k);
|
uint32_t calculateIndex(uint16_t i, uint16_t j, uint16_t k);
|
||||||
|
|
||||||
|
void stop();
|
||||||
void destroy();
|
void destroy();
|
||||||
std::unordered_map<std::uint32_t, Chunk::Chunk*>& getChunks();
|
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector();
|
||||||
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices();
|
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices();
|
||||||
void update(float deltaTime);
|
void update();
|
||||||
void updateChunk(uint32_t, uint16_t, uint16_t, uint16_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,22 +1,29 @@
|
||||||
#ifndef CHUNKMESH_H
|
#ifndef CHUNKMESH_H
|
||||||
#define CHUNKMESH_H
|
#define CHUNKMESH_H
|
||||||
|
|
||||||
#include <glad/glad.h>
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <oneapi/tbb/concurrent_queue.h>
|
||||||
|
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
#include "shader.hpp"
|
#include "shader.hpp"
|
||||||
|
|
||||||
namespace chunkmesher{
|
namespace chunkmesher{
|
||||||
void mesh(Chunk::Chunk* chunk);
|
struct MeshData{
|
||||||
void sendtogpu(Chunk::Chunk* chunk);
|
Chunk::Chunk* chunk;
|
||||||
void draw(Chunk::Chunk* chunk, glm::mat4 model);
|
std::vector<GLfloat> vertices;
|
||||||
|
std::vector<GLfloat> colors;
|
||||||
|
std::vector<GLuint> indices;
|
||||||
|
};
|
||||||
|
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue();
|
||||||
|
|
||||||
void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
|
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);
|
glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
#ifndef RENDERER_H
|
#ifndef RENDERER_H
|
||||||
#define RENDERER_H
|
#define RENDERER_H
|
||||||
|
|
||||||
|
#include <oneapi/tbb/concurrent_unordered_set.h>
|
||||||
|
#include <oneapi/tbb/concurrent_queue.h>
|
||||||
|
|
||||||
|
#include "chunk.hpp"
|
||||||
|
#include "chunkmesher.hpp"
|
||||||
#include "shader.hpp"
|
#include "shader.hpp"
|
||||||
|
|
||||||
namespace renderer{
|
namespace renderer{
|
||||||
|
typedef oneapi::tbb::concurrent_unordered_set<Chunk::Chunk*> RenderSet;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void render();
|
void render();
|
||||||
void destroy();
|
void destroy();
|
||||||
Shader* getRenderShader();
|
Shader* getRenderShader();
|
||||||
|
RenderSet& getChunksToRender();
|
||||||
|
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,5 +5,5 @@ set(SOURCE_FILES main.cpp chunk.cpp chunkmanager.cpp chunkmesher.cpp chunkgenera
|
||||||
|
|
||||||
add_executable(OpenGLTest ${SOURCE_FILES})
|
add_executable(OpenGLTest ${SOURCE_FILES})
|
||||||
|
|
||||||
target_link_libraries(OpenGLTest glfw glad glm)
|
target_link_libraries(OpenGLTest glfw tbb glad glm)
|
||||||
install(TARGETS OpenGLTest DESTINATION ${DIVISIBLE_INSTALL_BIN_DIR})
|
install(TARGETS OpenGLTest DESTINATION ${DIVISIBLE_INSTALL_BIN_DIR})
|
||||||
|
|
|
@ -19,7 +19,13 @@ namespace Chunk
|
||||||
{
|
{
|
||||||
this->position = pos;
|
this->position = pos;
|
||||||
this->setState(CHUNK_STATE_EMPTY, true);
|
this->setState(CHUNK_STATE_EMPTY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk ::~Chunk()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::createBuffers(){
|
||||||
glGenVertexArrays(1, &(this->VAO));
|
glGenVertexArrays(1, &(this->VAO));
|
||||||
glGenBuffers(1, &(this->colorBuffer));
|
glGenBuffers(1, &(this->colorBuffer));
|
||||||
glGenBuffers(1, &(this->VBO));
|
glGenBuffers(1, &(this->VBO));
|
||||||
|
@ -27,18 +33,12 @@ namespace Chunk
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk ::~Chunk()
|
void Chunk::deleteBuffers(){
|
||||||
{
|
|
||||||
glDeleteBuffers(1, &(this->colorBuffer));
|
glDeleteBuffers(1, &(this->colorBuffer));
|
||||||
glDeleteBuffers(1, &(this->VBO));
|
glDeleteBuffers(1, &(this->VBO));
|
||||||
glDeleteBuffers(1, &(this->EBO));
|
glDeleteBuffers(1, &(this->EBO));
|
||||||
glDeleteVertexArrays(1, &(this->VAO));
|
glDeleteVertexArrays(1, &(this->VAO));
|
||||||
|
|
||||||
vertices.clear();
|
|
||||||
indices.clear();
|
|
||||||
colors.clear();
|
|
||||||
|
|
||||||
mutex_state.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Block Chunk::getBlock(int x, int y, int z)
|
Block Chunk::getBlock(int x, int y, int z)
|
||||||
|
@ -60,8 +60,8 @@ namespace Chunk
|
||||||
void Chunk::setState(uint8_t nstate, bool value)
|
void Chunk::setState(uint8_t nstate, bool value)
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
this->state.set((size_t)nstate);
|
this->state.fetch_or(nstate);
|
||||||
else
|
else
|
||||||
this->state.reset((size_t)nstate);
|
this->state.fetch_and(~nstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#define NOISE_DIRT_MIN 2
|
#define NOISE_DIRT_MIN 2
|
||||||
#define NOISE_DIRT_X_MULT 0.001f
|
#define NOISE_DIRT_X_MULT 0.001f
|
||||||
#define NOISE_DIRT_Z_MULT 0.001f
|
#define NOISE_DIRT_Z_MULT 0.001f
|
||||||
#define NOISE_GRASS_X_MULT 0.035f
|
#define NOISE_GRASS_X_MULT 0.018f
|
||||||
#define NOISE_GRASS_Z_MULT 0.035f
|
#define NOISE_GRASS_Z_MULT 0.018f
|
||||||
|
|
||||||
void generatePyramid(Chunk::Chunk *chunk);
|
void generatePyramid(Chunk::Chunk *chunk);
|
||||||
void generateNoise(Chunk::Chunk *chunk);
|
void generateNoise(Chunk::Chunk *chunk);
|
||||||
|
@ -56,10 +56,12 @@ void generateNoise(Chunk::Chunk *chunk)
|
||||||
int z = HILBERT_XYZ_DECODE[s][2] + CHUNK_SIZE * chunk->getPosition().z;
|
int z = HILBERT_XYZ_DECODE[s][2] + CHUNK_SIZE * chunk->getPosition().z;
|
||||||
int d2 = HILBERT_XYZ_DECODE[s][0] * CHUNK_SIZE + HILBERT_XYZ_DECODE[s][2];
|
int d2 = HILBERT_XYZ_DECODE[s][0] * CHUNK_SIZE + HILBERT_XYZ_DECODE[s][2];
|
||||||
|
|
||||||
if (grassNoiseLUT[d2] == -1)
|
if (grassNoiseLUT[d2] == -1){
|
||||||
grassNoiseLUT[d2] = GRASS_OFFSET + (int)((0.5 + noiseGen1.eval(x * NOISE_GRASS_X_MULT, z * NOISE_GRASS_Z_MULT) * NOISE_GRASS_MULT));
|
grassNoiseLUT[d2] = GRASS_OFFSET + (int)((0.5 + noiseGen1.eval(x * NOISE_GRASS_X_MULT, z * NOISE_GRASS_Z_MULT) * NOISE_GRASS_MULT));
|
||||||
if (dirtNoiseLUT[d2] == -1)
|
}
|
||||||
|
if (dirtNoiseLUT[d2] == -1){
|
||||||
dirtNoiseLUT[d2] = NOISE_DIRT_MIN + (int)((0.5 + noiseGen2.eval(x * NOISE_DIRT_X_MULT, z * NOISE_DIRT_Z_MULT) * NOISE_DIRT_MULT));
|
dirtNoiseLUT[d2] = NOISE_DIRT_MIN + (int)((0.5 + noiseGen2.eval(x * NOISE_DIRT_X_MULT, z * NOISE_DIRT_Z_MULT) * NOISE_DIRT_MULT));
|
||||||
|
}
|
||||||
|
|
||||||
int grassNoise = grassNoiseLUT[d2];
|
int grassNoise = grassNoiseLUT[d2];
|
||||||
int dirtNoise = dirtNoiseLUT[d2];
|
int dirtNoise = dirtNoiseLUT[d2];
|
||||||
|
@ -84,6 +86,7 @@ void generateNoise(Chunk::Chunk *chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk->setBlocks(block_prev_start, CHUNK_VOLUME, block_prev);
|
chunk->setBlocks(block_prev_start, CHUNK_VOLUME, block_prev);
|
||||||
|
chunk->setState(Chunk::CHUNK_STATE_GENERATED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generateNoise3D(Chunk::Chunk *chunk) {
|
void generateNoise3D(Chunk::Chunk *chunk) {
|
||||||
|
|
|
@ -1,105 +1,40 @@
|
||||||
|
#include "chunkmanager.hpp"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <math.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
|
||||||
|
#include <oneapi/tbb/concurrent_hash_map.h>
|
||||||
|
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "chunkgenerator.hpp"
|
#include "chunkgenerator.hpp"
|
||||||
#include "chunkmanager.hpp"
|
|
||||||
#include "chunkmesher.hpp"
|
#include "chunkmesher.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
#include "renderer.hpp"
|
||||||
#include <atomic>
|
|
||||||
#include <iostream>
|
|
||||||
#include <math.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <set>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace chunkmanager
|
namespace chunkmanager
|
||||||
{
|
{
|
||||||
std::unordered_map<std::uint32_t, Chunk::Chunk *> chunks;
|
typedef oneapi::tbb::concurrent_hash_map<uint32_t, Chunk::Chunk*> ChunkTable;
|
||||||
|
ChunkTable chunks;
|
||||||
|
|
||||||
|
//std::unordered_map<std::uint32_t, Chunk::Chunk *> chunks;
|
||||||
std::array<std::array<int, 3>, chunks_volume> chunks_indices;
|
std::array<std::array<int, 3>, chunks_volume> chunks_indices;
|
||||||
|
|
||||||
// thread management
|
std::atomic_bool should_run;
|
||||||
std::mutex mutex_queue_generate;
|
|
||||||
std::mutex mutex_queue_mesh;
|
|
||||||
std::set<Chunk::Chunk *> to_generate;
|
|
||||||
std::set<Chunk::Chunk *> to_mesh;
|
|
||||||
std::atomic_bool generate_should_run;
|
|
||||||
std::atomic_bool mesh_should_run;
|
|
||||||
|
|
||||||
// update variables
|
int chunks_volume_real;
|
||||||
uint8_t f = 0;
|
std::thread init(){
|
||||||
int rr{RENDER_DISTANCE * RENDER_DISTANCE};
|
|
||||||
glm::vec3 cameraPos;
|
|
||||||
int chunkX, chunkY, chunkZ;
|
|
||||||
|
|
||||||
// disposal
|
|
||||||
std::unordered_map<uint32_t, float> to_delete;
|
|
||||||
std::set<uint32_t> to_delete_delete;
|
|
||||||
|
|
||||||
void mesh()
|
|
||||||
{
|
|
||||||
while (mesh_should_run)
|
|
||||||
if (mutex_queue_mesh.try_lock())
|
|
||||||
{
|
|
||||||
for (const auto &c : to_mesh)
|
|
||||||
{
|
|
||||||
if (c->mutex_state.try_lock())
|
|
||||||
{
|
|
||||||
chunkmesher::mesh(c);
|
|
||||||
c->setState(Chunk::CHUNK_STATE_MESHED, true);
|
|
||||||
c->mutex_state.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
to_mesh.clear();
|
|
||||||
mutex_queue_mesh.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate()
|
|
||||||
{
|
|
||||||
while (generate_should_run)
|
|
||||||
if (mutex_queue_generate.try_lock())
|
|
||||||
{
|
|
||||||
for (const auto &c : to_generate)
|
|
||||||
{
|
|
||||||
if (c->mutex_state.try_lock())
|
|
||||||
{
|
|
||||||
generateChunk(c);
|
|
||||||
c->setState(Chunk::CHUNK_STATE_GENERATED, true);
|
|
||||||
c->mutex_state.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
to_generate.clear();
|
|
||||||
mutex_queue_generate.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread initMeshThread()
|
|
||||||
{
|
|
||||||
mesh_should_run = true;
|
|
||||||
std::thread mesh_thread(mesh);
|
|
||||||
return mesh_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread initGenThread()
|
|
||||||
{
|
|
||||||
generate_should_run = true;
|
|
||||||
std::thread gen_thread(generate);
|
|
||||||
return gen_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(){
|
|
||||||
int index{0};
|
int index{0};
|
||||||
|
int rr{RENDER_DISTANCE * RENDER_DISTANCE};
|
||||||
|
|
||||||
int xp{0}, x{0};
|
int xp{0}, x{0};
|
||||||
bool b = true;
|
bool b = true;
|
||||||
|
|
||||||
// Iterate over all chunks, in concentric spheres starting fron the player and going
|
// Iterate over all chunks, in concentric spheres starting fron the player and going outwards. Alternate left and right
|
||||||
// outwards. Alternate left and right
|
|
||||||
// Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r²
|
// Eq. of the sphere (x - a)² + (y - b)² + (z - c)² = r²
|
||||||
while (xp <= RENDER_DISTANCE)
|
while (xp <= RENDER_DISTANCE)
|
||||||
{
|
{
|
||||||
|
@ -131,168 +66,57 @@ namespace chunkmanager
|
||||||
}
|
}
|
||||||
else b = false;
|
else b = false;
|
||||||
}
|
}
|
||||||
|
chunks_volume_real = index;
|
||||||
|
|
||||||
|
// Also init mesh data queue
|
||||||
|
for(int i = 0; i < 10; i++)
|
||||||
|
chunkmesher::getMeshDataQueue().push(new chunkmesher::MeshData());
|
||||||
|
|
||||||
|
should_run = true;
|
||||||
|
std::thread update_thread (update);
|
||||||
|
return update_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(float deltaTime)
|
oneapi::tbb::concurrent_queue<Chunk::Chunk*> chunks_todelete;
|
||||||
{
|
int nUnloaded{0};
|
||||||
// Try to lock resources
|
void update(){
|
||||||
f = 0;
|
while(should_run) {
|
||||||
f |= mutex_queue_generate.try_lock();
|
int chunkX=static_cast<int>(theCamera.getAtomicPosX() / CHUNK_SIZE);
|
||||||
f |= mutex_queue_mesh.try_lock() << 1;
|
int chunkY=static_cast<int>(theCamera.getAtomicPosY() / CHUNK_SIZE);
|
||||||
|
int chunkZ=static_cast<int>(theCamera.getAtomicPosZ() / CHUNK_SIZE);
|
||||||
|
|
||||||
cameraPos = theCamera.getPos();
|
// Update other chunks
|
||||||
chunkX=static_cast<int>(cameraPos.x) / CHUNK_SIZE;
|
for(int i = 0; i < chunks_volume_real; i++) {
|
||||||
chunkY=static_cast<int>(cameraPos.y) / CHUNK_SIZE;
|
const uint16_t x = chunks_indices[i][0] + chunkX;
|
||||||
chunkZ=static_cast<int>(cameraPos.z) / CHUNK_SIZE;
|
const uint16_t y = chunks_indices[i][1] + chunkY;
|
||||||
|
const uint16_t z = chunks_indices[i][2] + chunkZ;
|
||||||
|
const uint32_t index = calculateIndex(x, y, z);
|
||||||
|
|
||||||
// Use time in float to be consistent with glfw
|
if(x > 1023 || y > 1023 || z > 1023) continue;
|
||||||
float currentTime = glfwGetTime();
|
|
||||||
|
|
||||||
// Check for far chunks that need to be cleaned up from memory
|
ChunkTable::accessor a;
|
||||||
int nUnloaded{0};
|
if(!chunks.find(a, index)) chunks.emplace(a, std::make_pair(index, new Chunk::Chunk(glm::vec3(x,y,z))));
|
||||||
for(const auto& n : chunks){
|
|
||||||
Chunk::Chunk* c = n.second;
|
|
||||||
int x{(int)(c->getPosition().x)};
|
|
||||||
int y{(int)(c->getPosition().y)};
|
|
||||||
int z{(int)(c->getPosition().z)};
|
|
||||||
if( (chunkX-x)*(chunkX-x) + (chunkY-y)*(chunkY-y) + (chunkZ-z)*(chunkZ-z) >=
|
|
||||||
(int)(RENDER_DISTANCE*1.5)*(int)(RENDER_DISTANCE*1.5))
|
|
||||||
if(to_delete.find(n.first) == to_delete.end())
|
|
||||||
to_delete.insert(std::make_pair(n.first, currentTime));
|
|
||||||
}
|
|
||||||
for(const auto& n :to_delete){
|
|
||||||
if( currentTime>=n.second + UNLOAD_TIMEOUT) {
|
|
||||||
delete chunks.at(n.first);
|
|
||||||
chunks.erase(n.first);
|
|
||||||
nUnloaded++;
|
|
||||||
|
|
||||||
// Delete afterwards to avoid exception due to invalid iterators
|
if(! (a->second->getState(Chunk::CHUNK_STATE_GENERATED))) generateChunk(a->second);
|
||||||
to_delete_delete.insert(n.first);
|
if(! (a->second->getState(Chunk::CHUNK_STATE_MESHED))) chunkmesher::mesh(a->second);
|
||||||
|
|
||||||
|
renderer::getChunksToRender().insert(a->second);
|
||||||
|
|
||||||
|
a.release();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for(uint32_t i : to_delete_delete) to_delete.erase(i);
|
|
||||||
to_delete_delete.clear();
|
|
||||||
if(nUnloaded) std::cout << "Unloaded " << nUnloaded << " chunks\n";
|
|
||||||
|
|
||||||
for(int i = 0; i < chunks_volume; i++)
|
Chunk::Chunk* n;
|
||||||
updateChunk(calculateIndex(chunks_indices[i][0] + chunkX,
|
nUnloaded = 0;
|
||||||
chunks_indices[i][1] + chunkY,
|
while(chunks_todelete.try_pop(n)){
|
||||||
chunks_indices[i][2] + chunkZ),
|
int x = static_cast<uint16_t>(n->getPosition().x);
|
||||||
chunks_indices[i][0] + chunkX,
|
int y = static_cast<uint16_t>(n->getPosition().y);
|
||||||
chunks_indices[i][1] + chunkY,
|
int z = static_cast<uint16_t>(n->getPosition().z);
|
||||||
chunks_indices[i][2] + chunkZ);
|
if(x > 1023 || y > 1023 || z > 1023) continue;
|
||||||
|
const uint32_t index = calculateIndex(x, y, z);
|
||||||
|
|
||||||
// Unlock mutexes if previously locked. Unlocking a mutex not locked by the current thread
|
delete n;
|
||||||
// or already locked is undefined behaviour, so checking has to be done
|
chunks.erase(index);
|
||||||
if ((f & 1))
|
nUnloaded++;
|
||||||
mutex_queue_generate.unlock();
|
|
||||||
if ((f & 2))
|
|
||||||
mutex_queue_mesh.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generation and meshing happen in two separate threads from the main one
|
|
||||||
// Chunk states are used to decide which actions need to be done on the chunk and sets+mutexes
|
|
||||||
// to pass the chunks to be operated on between the threads.
|
|
||||||
// Uploading data to GPU still needs to be done in the main thread, or another OpenGL context
|
|
||||||
// needs to be opened, which further complicates stuff.
|
|
||||||
void updateChunk(uint32_t index, uint16_t i, uint16_t j, uint16_t k)
|
|
||||||
{
|
|
||||||
if (chunks.find(index) == chunks.end())
|
|
||||||
{
|
|
||||||
Chunk::Chunk *c = new Chunk::Chunk(glm::vec3(i, j, k));
|
|
||||||
chunks.insert(std::make_pair(index, c));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Chunk::Chunk *c = chunks.at(index);
|
|
||||||
|
|
||||||
if (!(c->mutex_state.try_lock()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!c->getState(Chunk::CHUNK_STATE_GENERATED))
|
|
||||||
{
|
|
||||||
if (f & 1)
|
|
||||||
to_generate.insert(c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!c->getState(Chunk::CHUNK_STATE_MESHED))
|
|
||||||
{
|
|
||||||
if (f & 2)
|
|
||||||
to_mesh.insert(c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) chunkmesher::sendtogpu(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c->mutex_state.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void blockpick(bool place){
|
|
||||||
// cast a ray from the camera in the direction pointed by the camera itself
|
|
||||||
glm::vec3 pos = cameraPos;
|
|
||||||
for(float t = 0.0; t <= 10.0; t += 0.5){
|
|
||||||
// traverse the ray a block at the time
|
|
||||||
pos = theCamera.getPos() + t * theCamera.getFront();
|
|
||||||
|
|
||||||
// get which chunk and block the ray is at
|
|
||||||
int px = ((int)(pos.x))/CHUNK_SIZE;
|
|
||||||
int py = ((int)(pos.y))/CHUNK_SIZE;
|
|
||||||
int pz = ((int)(pos.z))/CHUNK_SIZE;
|
|
||||||
int bx = pos.x - px*CHUNK_SIZE;
|
|
||||||
int by = pos.y - py*CHUNK_SIZE;
|
|
||||||
int bz = pos.z - pz*CHUNK_SIZE;
|
|
||||||
|
|
||||||
// exit early if the position is invalid or the chunk does not exist
|
|
||||||
if(px < 0 || py < 0 || pz < 0) return;
|
|
||||||
if(chunks.find(calculateIndex(px, py, pz)) == chunks.end()) return;
|
|
||||||
|
|
||||||
Chunk::Chunk* c = chunks.at(calculateIndex(px, py, pz));
|
|
||||||
Block b = c->getBlock(bx, by, bz);
|
|
||||||
|
|
||||||
// if the block is non empty
|
|
||||||
if(b != Block::AIR){
|
|
||||||
|
|
||||||
// if placing a new block
|
|
||||||
if(place){
|
|
||||||
// Go half a block backwards on the ray, to check the block where the ray was
|
|
||||||
// coming from
|
|
||||||
// Doing this and not using normal adds the unexpected (and unwanted) ability to
|
|
||||||
// place blocks diagonally, without faces colliding with the block that has
|
|
||||||
// been clicked
|
|
||||||
pos -= theCamera.getFront()*0.5f;
|
|
||||||
|
|
||||||
int px1 = ((int)(pos.x))/CHUNK_SIZE;
|
|
||||||
int py1 = ((int)(pos.y))/CHUNK_SIZE;
|
|
||||||
int pz1 = ((int)(pos.z))/CHUNK_SIZE;
|
|
||||||
int bx1 = pos.x - px1*CHUNK_SIZE;
|
|
||||||
int by1 = pos.y - py1*CHUNK_SIZE;
|
|
||||||
int bz1 = pos.z - pz1*CHUNK_SIZE;
|
|
||||||
|
|
||||||
// exit early if the position is invalid or the chunk does not exist
|
|
||||||
if(px1 < 0 || py1 < 0 || pz1 < 0) return;
|
|
||||||
if(chunks.find(calculateIndex(px1, py1, pz1)) == chunks.end()) return;
|
|
||||||
|
|
||||||
Chunk::Chunk* c1 = chunks.at(calculateIndex(px1, py1, pz1));
|
|
||||||
// place the new block (only stone for now)
|
|
||||||
c1->setBlock( Block::STONE, bx1, by1, bz1);
|
|
||||||
|
|
||||||
// update the mesh of the chunk
|
|
||||||
chunkmesher::mesh(c1);
|
|
||||||
// mark the mesh of the chunk the be updated on the gpu
|
|
||||||
c1->setState(Chunk::CHUNK_STATE_MESH_LOADED, false);
|
|
||||||
}else{
|
|
||||||
// replace the current block with air to remove it
|
|
||||||
c->setBlock( Block::AIR, bx, by, bz);
|
|
||||||
|
|
||||||
// update the mesh of the chunk
|
|
||||||
chunkmesher::mesh(c);
|
|
||||||
// mark the mesh of the chunk the be updated on the gpu
|
|
||||||
c->setState(Chunk::CHUNK_STATE_MESH_LOADED, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,21 +126,14 @@ namespace chunkmanager
|
||||||
return i | (j << 10) | (k << 20);
|
return i | (j << 10) | (k << 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::uint32_t, Chunk::Chunk*>& getChunks(){ return chunks; }
|
oneapi::tbb::concurrent_queue<Chunk::Chunk*>& getDeleteVector(){ return chunks_todelete; }
|
||||||
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; }
|
std::array<std::array<int, 3>, chunks_volume>& getChunksIndices(){ return chunks_indices; }
|
||||||
|
|
||||||
void destroy()
|
void stop() { should_run=false; }
|
||||||
{
|
void destroy(){
|
||||||
for (auto &n : chunks)
|
/*for(const auto& n : chunks){
|
||||||
delete n.second;
|
delete n.second;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void stopGenThread(){
|
|
||||||
generate_should_run = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopMeshThread(){
|
|
||||||
mesh_should_run = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,13 +5,20 @@
|
||||||
#include "chunk.hpp"
|
#include "chunk.hpp"
|
||||||
#include "chunkmesher.hpp"
|
#include "chunkmesher.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
#include "renderer.hpp"
|
||||||
#include "spacefilling.hpp"
|
#include "spacefilling.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
namespace chunkmesher{
|
namespace chunkmesher{
|
||||||
|
|
||||||
|
oneapi::tbb::concurrent_queue<MeshData*> MeshDataQueue;
|
||||||
|
|
||||||
|
oneapi::tbb::concurrent_queue<MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
||||||
|
|
||||||
void mesh(Chunk::Chunk* chunk)
|
void mesh(Chunk::Chunk* chunk)
|
||||||
{
|
{
|
||||||
|
MeshData* mesh_data;
|
||||||
|
if(!MeshDataQueue.try_pop(mesh_data)) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Taking inspiration from 0fps and the jme3 porting at
|
* Taking inspiration from 0fps and the jme3 porting at
|
||||||
|
@ -29,18 +36,25 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Cleanup previous data
|
// Cleanup previous data
|
||||||
chunk->vertices.clear();
|
chunk->numVertices = 0;
|
||||||
chunk->indices.clear();
|
mesh_data->chunk = chunk;
|
||||||
chunk->colors.clear();
|
mesh_data->vertices.clear();
|
||||||
chunk->vIndex = 0;
|
mesh_data->indices.clear();
|
||||||
|
mesh_data->colors.clear();
|
||||||
|
|
||||||
// Abort if chunk is empty
|
// Abort if chunk is empty
|
||||||
if(chunk->getState(Chunk::CHUNK_STATE_EMPTY)) return;
|
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
|
// 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);
|
std::unique_ptr<Block[]> blocks = chunk->getBlocksArray(&length);
|
||||||
if(length == 0) {
|
if(length == 0) {
|
||||||
|
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||||
|
renderer::getMeshDataQueue().push(mesh_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +160,7 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
dv[2] = 0;
|
dv[2] = 0;
|
||||||
dv[v] = h;
|
dv[v] = h;
|
||||||
|
|
||||||
quad(chunk, glm::vec3(x[0], x[1], x[2]),
|
quad(mesh_data, glm::vec3(x[0], x[1], x[2]),
|
||||||
glm::vec3(x[0] + du[0], x[1] + du[1], x[2] + du[2]),
|
glm::vec3(x[0] + du[0], x[1] + du[1], x[2] + du[2]),
|
||||||
glm::vec3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1],
|
glm::vec3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1],
|
||||||
x[2] + du[2] + dv[2]),
|
x[2] + du[2] + dv[2]),
|
||||||
|
@ -180,18 +194,23 @@ void mesh(Chunk::Chunk* chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk->setState(Chunk::CHUNK_STATE_MESHED, true);
|
||||||
|
renderer::getMeshDataQueue().push(mesh_data);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendtogpu(Chunk::Chunk* chunk)
|
void sendtogpu(MeshData* mesh_data)
|
||||||
{
|
{
|
||||||
if (chunk->vIndex > 0)
|
if (mesh_data->chunk->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).
|
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
|
||||||
glBindVertexArray(chunk->VAO);
|
glBindVertexArray(mesh_data->chunk->VAO);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, chunk->VBO);
|
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->VBO);
|
||||||
glBufferData(GL_ARRAY_BUFFER, chunk->vertices.size() * sizeof(GLfloat), &(chunk->vertices[0]), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, mesh_data->vertices.size() * sizeof(GLfloat), &(mesh_data->vertices[0]), GL_STATIC_DRAW);
|
||||||
|
|
||||||
// position attribute
|
// position attribute
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
|
||||||
|
@ -202,12 +221,12 @@ void sendtogpu(Chunk::Chunk* chunk)
|
||||||
sizeof(float)));
|
sizeof(float)));
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, chunk->EBO);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_data->chunk->EBO);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, chunk->indices.size() * sizeof(GLuint), &(chunk->indices[0]), GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh_data->indices.size() * sizeof(GLuint), &(mesh_data->indices[0]), GL_STATIC_DRAW);
|
||||||
|
|
||||||
// texcoords attribute
|
// texcoords attribute
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, chunk->colorBuffer);
|
glBindBuffer(GL_ARRAY_BUFFER, mesh_data->chunk->colorBuffer);
|
||||||
glBufferData(GL_ARRAY_BUFFER, chunk->colors.size() * sizeof(GLfloat), &(chunk->colors[0]), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, mesh_data->colors.size() * sizeof(GLfloat), &(mesh_data->colors[0]), GL_STATIC_DRAW);
|
||||||
|
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
|
||||||
|
@ -215,119 +234,118 @@ void sendtogpu(Chunk::Chunk* chunk)
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
// save the number of indices of the mesh, it is needed later for drawing
|
// save the number of indices of the mesh, it is needed later for drawing
|
||||||
chunk->vIndex = (GLuint)(chunk->indices.size());
|
mesh_data->chunk->numVertices = (GLuint)(mesh_data->indices.size());
|
||||||
|
|
||||||
// once data has been sent to the GPU, it can be cleared from system RAM
|
// once data has been sent to the GPU, it can be cleared from system RAM
|
||||||
chunk->vertices.clear();
|
mesh_data->vertices.clear();
|
||||||
chunk->indices.clear();
|
mesh_data->indices.clear();
|
||||||
chunk->colors.clear();
|
mesh_data->colors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark the chunk mesh has loaded on GPU
|
// mark the chunk mesh has loaded on GPU
|
||||||
chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
|
mesh_data->chunk->setState(Chunk::CHUNK_STATE_MESH_LOADED, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void quad(Chunk::Chunk* chunk, glm::vec3 bottomLeft, glm::vec3 topLeft, glm::vec3 topRight,
|
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)
|
glm::vec3 bottomRight, glm::vec3 normal, Block block, int dim, bool backFace)
|
||||||
{
|
{
|
||||||
|
mesh_data->vertices.push_back(bottomLeft.x);
|
||||||
|
mesh_data->vertices.push_back(bottomLeft.y);
|
||||||
|
mesh_data->vertices.push_back(bottomLeft.z);
|
||||||
|
mesh_data->vertices.push_back(normal.x);
|
||||||
|
mesh_data->vertices.push_back(normal.y);
|
||||||
|
mesh_data->vertices.push_back(normal.z);
|
||||||
|
|
||||||
chunk->vertices.push_back(bottomLeft.x);
|
mesh_data->vertices.push_back(bottomRight.x);
|
||||||
chunk->vertices.push_back(bottomLeft.y);
|
mesh_data->vertices.push_back(bottomRight.y);
|
||||||
chunk->vertices.push_back(bottomLeft.z);
|
mesh_data->vertices.push_back(bottomRight.z);
|
||||||
chunk->vertices.push_back(normal.x);
|
mesh_data->vertices.push_back(normal.x);
|
||||||
chunk->vertices.push_back(normal.y);
|
mesh_data->vertices.push_back(normal.y);
|
||||||
chunk->vertices.push_back(normal.z);
|
mesh_data->vertices.push_back(normal.z);
|
||||||
|
|
||||||
chunk->vertices.push_back(bottomRight.x);
|
mesh_data->vertices.push_back(topLeft.x);
|
||||||
chunk->vertices.push_back(bottomRight.y);
|
mesh_data->vertices.push_back(topLeft.y);
|
||||||
chunk->vertices.push_back(bottomRight.z);
|
mesh_data->vertices.push_back(topLeft.z);
|
||||||
chunk->vertices.push_back(normal.x);
|
mesh_data->vertices.push_back(normal.x);
|
||||||
chunk->vertices.push_back(normal.y);
|
mesh_data->vertices.push_back(normal.y);
|
||||||
chunk->vertices.push_back(normal.z);
|
mesh_data->vertices.push_back(normal.z);
|
||||||
|
|
||||||
chunk->vertices.push_back(topLeft.x);
|
mesh_data->vertices.push_back(topRight.x);
|
||||||
chunk->vertices.push_back(topLeft.y);
|
mesh_data->vertices.push_back(topRight.y);
|
||||||
chunk->vertices.push_back(topLeft.z);
|
mesh_data->vertices.push_back(topRight.z);
|
||||||
chunk->vertices.push_back(normal.x);
|
mesh_data->vertices.push_back(normal.x);
|
||||||
chunk->vertices.push_back(normal.y);
|
mesh_data->vertices.push_back(normal.y);
|
||||||
chunk->vertices.push_back(normal.z);
|
mesh_data->vertices.push_back(normal.z);
|
||||||
|
|
||||||
chunk->vertices.push_back(topRight.x);
|
|
||||||
chunk->vertices.push_back(topRight.y);
|
|
||||||
chunk->vertices.push_back(topRight.z);
|
|
||||||
chunk->vertices.push_back(normal.x);
|
|
||||||
chunk->vertices.push_back(normal.y);
|
|
||||||
chunk->vertices.push_back(normal.z);
|
|
||||||
|
|
||||||
// texcoords
|
// texcoords
|
||||||
if(dim == 0){
|
if(dim == 0){
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(bottomRight.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(bottomRight.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(bottomRight.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(bottomRight.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topLeft.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(topLeft.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(topLeft.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(topLeft.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topRight.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(topRight.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(topRight.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(topRight.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
}else if(dim == 1){
|
}else if(dim == 1){
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(bottomRight.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(bottomRight.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(bottomRight.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(bottomRight.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topLeft.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(topLeft.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(topLeft.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(topLeft.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topRight.z - bottomLeft.z));
|
mesh_data->colors.push_back(abs(topRight.z - bottomLeft.z));
|
||||||
chunk->colors.push_back(abs(topRight.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(topRight.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
}else{
|
}else{
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(0);
|
mesh_data->colors.push_back(0);
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(bottomRight.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(bottomRight.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(abs(bottomRight.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(bottomRight.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topLeft.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(topLeft.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(abs(topLeft.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(topLeft.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
|
|
||||||
chunk->colors.push_back(abs(topRight.x - bottomLeft.x));
|
mesh_data->colors.push_back(abs(topRight.x - bottomLeft.x));
|
||||||
chunk->colors.push_back(abs(topRight.y - bottomLeft.y));
|
mesh_data->colors.push_back(abs(topRight.y - bottomLeft.y));
|
||||||
chunk->colors.push_back(((int)block) - 2);
|
mesh_data->colors.push_back(((int)block) - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backFace)
|
if (backFace)
|
||||||
{
|
{
|
||||||
chunk->indices.push_back(chunk->vIndex + 2);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
|
||||||
chunk->indices.push_back(chunk->vIndex);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices);
|
||||||
chunk->indices.push_back(chunk->vIndex + 1);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
|
||||||
chunk->indices.push_back(chunk->vIndex + 1);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
|
||||||
chunk->indices.push_back(chunk->vIndex + 3);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 3);
|
||||||
chunk->indices.push_back(chunk->vIndex + 2);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
chunk->indices.push_back(chunk->vIndex + 2);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
|
||||||
chunk->indices.push_back(chunk->vIndex + 3);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 3);
|
||||||
chunk->indices.push_back(chunk->vIndex + 1);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
|
||||||
chunk->indices.push_back(chunk->vIndex + 1);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 1);
|
||||||
chunk->indices.push_back(chunk->vIndex);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices);
|
||||||
chunk->indices.push_back(chunk->vIndex + 2);
|
mesh_data->indices.push_back(mesh_data->chunk->numVertices + 2);
|
||||||
}
|
}
|
||||||
chunk->vIndex += 4;
|
mesh_data->chunk->numVertices += 4;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
17
src/main.cpp
17
src/main.cpp
|
@ -63,9 +63,7 @@ int main()
|
||||||
|
|
||||||
SpaceFilling::initLUT();
|
SpaceFilling::initLUT();
|
||||||
renderer::init();
|
renderer::init();
|
||||||
chunkmanager::init();
|
std::thread chunkmanager_thread = chunkmanager::init();
|
||||||
std::thread genThread = chunkmanager::initGenThread();
|
|
||||||
std::thread meshThread = chunkmanager::initMeshThread();
|
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window))
|
while (!glfwWindowShouldClose(window))
|
||||||
{
|
{
|
||||||
|
@ -94,9 +92,6 @@ int main()
|
||||||
// Reset blockping timeout if 200ms have passed
|
// Reset blockping timeout if 200ms have passed
|
||||||
if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false;
|
if(glfwGetTime() - lastBlockPick > 0.1) blockpick = false;
|
||||||
|
|
||||||
// ChunkManager
|
|
||||||
chunkmanager::update(deltaTime);
|
|
||||||
|
|
||||||
// Render pass
|
// Render pass
|
||||||
renderer::render();
|
renderer::render();
|
||||||
|
|
||||||
|
@ -106,10 +101,8 @@ int main()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop threads and wait for them to finish
|
// Stop threads and wait for them to finish
|
||||||
chunkmanager::stopGenThread();
|
chunkmanager::stop();
|
||||||
chunkmanager::stopMeshThread();
|
chunkmanager_thread.join();
|
||||||
genThread.join();
|
|
||||||
meshThread.join();
|
|
||||||
|
|
||||||
// Cleanup allocated memory
|
// Cleanup allocated memory
|
||||||
chunkmanager::destroy();
|
chunkmanager::destroy();
|
||||||
|
@ -136,13 +129,13 @@ void processInput(GLFWwindow *window)
|
||||||
glfwSetWindowShouldClose(window, true);
|
glfwSetWindowShouldClose(window, true);
|
||||||
|
|
||||||
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS && !blockpick){
|
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS && !blockpick){
|
||||||
chunkmanager::blockpick(false);
|
//chunkmanager::blockpick(false);
|
||||||
blockpick=true;
|
blockpick=true;
|
||||||
lastBlockPick=glfwGetTime();
|
lastBlockPick=glfwGetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS && !blockpick){
|
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS && !blockpick){
|
||||||
chunkmanager::blockpick(true);
|
//chunkmanager::blockpick(true);
|
||||||
blockpick=true;
|
blockpick=true;
|
||||||
lastBlockPick=glfwGetTime();
|
lastBlockPick=glfwGetTime();
|
||||||
}
|
}
|
||||||
|
|
124
src/renderer.cpp
124
src/renderer.cpp
|
@ -1,16 +1,25 @@
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
|
#include <oneapi/tbb/concurrent_vector.h>
|
||||||
|
#include <oneapi/tbb/concurrent_queue.h>
|
||||||
|
|
||||||
#include "chunkmanager.hpp"
|
#include "chunkmanager.hpp"
|
||||||
#include "chunkmesher.hpp"
|
#include "chunkmesher.hpp"
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
|
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
namespace renderer{
|
namespace renderer{
|
||||||
|
RenderSet chunks_torender;
|
||||||
|
oneapi::tbb::concurrent_vector<Chunk::Chunk*> render_todelete;
|
||||||
|
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*> MeshDataQueue;
|
||||||
|
|
||||||
Shader* theShader;
|
Shader* theShader;
|
||||||
GLuint chunkTexture;
|
GLuint chunkTexture;
|
||||||
|
|
||||||
Shader* getRenderShader() { return theShader; }
|
Shader* getRenderShader() { return theShader; }
|
||||||
|
RenderSet& getChunksToRender(){ return chunks_torender; }
|
||||||
|
oneapi::tbb::concurrent_queue<chunkmesher::MeshData*>& getMeshDataQueue(){ return MeshDataQueue; }
|
||||||
|
|
||||||
|
|
||||||
void init(){
|
void init(){
|
||||||
// Create Shader
|
// Create Shader
|
||||||
|
@ -40,61 +49,92 @@ namespace renderer{
|
||||||
int total{0}, toGpu{0};
|
int total{0}, toGpu{0};
|
||||||
glm::vec4 frustumPlanes[6];
|
glm::vec4 frustumPlanes[6];
|
||||||
theCamera.getFrustumPlanes(frustumPlanes, true);
|
theCamera.getFrustumPlanes(frustumPlanes, true);
|
||||||
|
glm::vec3 cameraPos = theCamera.getPos();
|
||||||
glm::vec3 cameraPos = theCamera.getPos();
|
glm::vec3 cameraChunkPos = cameraPos / static_cast<float>(CHUNK_SIZE);
|
||||||
int chunkX=static_cast<int>(cameraPos.x) / CHUNK_SIZE;
|
|
||||||
int chunkY=static_cast<int>(cameraPos.y) / CHUNK_SIZE;
|
|
||||||
int chunkZ=static_cast<int>(cameraPos.z) / CHUNK_SIZE;
|
|
||||||
|
|
||||||
theShader->use();
|
theShader->use();
|
||||||
theShader->setVec3("viewPos", cameraPos);
|
theShader->setVec3("viewPos", cameraPos);
|
||||||
for(int i = 0; i < chunks_volume; i++) {
|
|
||||||
Chunk::Chunk* c = chunkmanager::getChunks().at(chunkmanager::calculateIndex(chunkmanager::getChunksIndices()[i][0] +
|
|
||||||
chunkX, chunkmanager::getChunksIndices()[i][1] + chunkY, chunkmanager::getChunksIndices()[i][2] + chunkZ));
|
|
||||||
// Frustum Culling of chunk
|
|
||||||
total++;
|
|
||||||
|
|
||||||
glm::vec3 chunk = c->getPosition();
|
chunkmesher::MeshData* m;
|
||||||
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);
|
while(MeshDataQueue.try_pop(m)){
|
||||||
glm::mat4 model = glm::translate(glm::mat4(1.0), ((float)CHUNK_SIZE) * chunk);
|
chunkmesher::sendtogpu(m);
|
||||||
|
chunkmesher::getMeshDataQueue().push(m);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if all the corners of the chunk are outside any of the planes
|
for(auto& c : chunks_torender){
|
||||||
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
if(! (c->getState(Chunk::CHUNK_STATE_MESHED))) continue;
|
||||||
// plane against each corner of the chunk
|
|
||||||
bool out=false;
|
float dist = glm::distance(c->getPosition(), cameraChunkPos);
|
||||||
int a{0};
|
if(dist <= static_cast<float>(RENDER_DISTANCE)){
|
||||||
for(int p = 0; p < 6; p++){
|
if(!c->getState(Chunk::CHUNK_STATE_MESH_LOADED)) continue;
|
||||||
a = 0;
|
|
||||||
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
|
||||||
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
|
||||||
|
|
||||||
if(a==8){
|
// reset out-of-vision and unload flags
|
||||||
out=true;
|
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, false);
|
||||||
break;
|
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||||
|
|
||||||
|
// Perform frustum culling and eventually render
|
||||||
|
glm::vec3 chunk = c->getPosition();
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Check if all the corners of the chunk are outside any of the planes
|
||||||
|
// TODO (?) implement frustum culling as per (Inigo Quilez)[https://iquilezles.org/articles/frustumcorrect/], and check each
|
||||||
|
// plane against each corner of the chunk
|
||||||
|
bool out=false;
|
||||||
|
int a{0};
|
||||||
|
for(int p = 0; p < 6; p++){
|
||||||
|
a = 0;
|
||||||
|
for(int i = 0; i < 8; i++) a += glm::dot(frustumPlanes[p], glm::vec4(chunkW.x + ((float)(i & 1))*CHUNK_SIZE, chunkW.y
|
||||||
|
+ ((float)((i & 2) >> 1))*CHUNK_SIZE, chunkW.z + ((float)((i & 4) >> 2))*CHUNK_SIZE, 1.0)) < 0.0;
|
||||||
|
|
||||||
|
if(a==8){
|
||||||
|
out=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
{
|
|
||||||
toGpu++;
|
|
||||||
|
|
||||||
if(c->getState(Chunk::CHUNK_STATE_MESH_LOADED) && c->vIndex > 0)
|
|
||||||
{
|
{
|
||||||
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode
|
if(c->numVertices > 0)
|
||||||
theShader->setMat4("model", model);
|
{
|
||||||
theShader->setMat4("view", theCamera.getView());
|
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // wireframe mode
|
||||||
theShader->setMat4("projection", theCamera.getProjection());
|
theShader->setMat4("model", model);
|
||||||
|
theShader->setMat4("view", theCamera.getView());
|
||||||
|
theShader->setMat4("projection", theCamera.getProjection());
|
||||||
|
|
||||||
glBindVertexArray(c->VAO);
|
glBindVertexArray(c->VAO);
|
||||||
glDrawElements(GL_TRIANGLES, c->vIndex , GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, c->numVertices , GL_UNSIGNED_INT, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
// When the chunk is outside render distance
|
||||||
|
|
||||||
|
if(c->getState(Chunk::CHUNK_STATE_OUTOFVISION)){
|
||||||
|
if(glfwGetTime() - c->unload_timer > UNLOAD_TIMEOUT){
|
||||||
|
// If chunk was already out and enough time has passed
|
||||||
|
// Mark the chunk to be unloaded
|
||||||
|
// And mark is to be removed from the render set
|
||||||
|
render_todelete.push_back(c);
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
// Mark has out of vision and annotate when it started
|
||||||
|
c->setState(Chunk::CHUNK_STATE_OUTOFVISION, true);
|
||||||
|
c->setState(Chunk::CHUNK_STATE_UNLOADED, false);
|
||||||
|
c->unload_timer = glfwGetTime();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::cout << "Chunks to mesh: " << to_mesh.size() << "\n";
|
for(auto& c : render_todelete){
|
||||||
//std::cout << "Chunks to generate: " << to_generate.size() << "\n";
|
// we can get away with unsafe erase as access to the container is only done by this
|
||||||
//std::cout << "Total chunks to draw: " << total << ". Sent to GPU: " << toGpu << "\n";
|
// thread
|
||||||
|
c->deleteBuffers();
|
||||||
|
chunks_torender.unsafe_erase(c);
|
||||||
|
chunkmanager::getDeleteVector().push(c);
|
||||||
|
}
|
||||||
|
render_todelete.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy(){
|
void destroy(){
|
||||||
|
|
Loading…
Reference in New Issue