get rid of the chunk shit, broken sphere..

This commit is contained in:
Evert Prants 2020-03-21 17:58:23 +02:00
parent 736e7a19b1
commit cfbcc73549
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
8 changed files with 232 additions and 721 deletions

View File

@ -31,6 +31,7 @@ endif()
add_executable(${VOXSPATIUM_EXECUTABLE} ${SOURCES})
# Include GL
set(OpenGL_GL_PREFERENCE "LEGACY")
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries(${VOXSPATIUM_EXECUTABLE} ${OPENGL_LIBRARIES})
@ -38,7 +39,7 @@ target_link_libraries(${VOXSPATIUM_EXECUTABLE} ${OPENGL_LIBRARIES})
# Include GLEW
find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_PATH})
target_link_libraries(${VOXSPATIUM_EXECUTABLE} ${GLEW_LIBRARY})
target_link_libraries(${VOXSPATIUM_EXECUTABLE} ${GLEW_LIBRARIES})
# Include SDL
INCLUDE(FindPkgConfig)

View File

@ -160,7 +160,7 @@ void Application::run()
Input::getInstance().setMouseCoords(m_width/2, m_height/2);
glEnable(GL_DEPTH_TEST);
Planet* pl = new Planet(glm::vec3(0.0f,0.0f,0.0f), 4);
Planet* pl = new Planet(glm::vec3(0.0f,0.0f,0.0f), 128.0f);
// Create the shader and link them together
Shader& chunkShader = Shader::createShader("data/shaders/chunk.vert", "data/shaders/chunk.frag");
chunkShader.linkShaders();

View File

@ -226,7 +226,7 @@ void Camera::updateProjection(void)
{
// Recalculate the projection matrix
glm::vec2 screenDims = Application::getInstance().getScreenDimensions();
m_projection = glm::perspective(getFOV(), (GLfloat)screenDims.x/(GLfloat)screenDims.y, 0.1f, 100.0f);
m_projection = glm::perspective(getFOV(), (GLfloat)screenDims.x/(GLfloat)screenDims.y, 0.1f, 1000.0f);
}
void Camera::updateCameraVectors(void)

View File

@ -1,266 +0,0 @@
#include "Chunk.h"
#include "planet/PlanetFace.h"
const glm::vec3 FACE_VERTEX[6][4] = {
// Bottom
{
glm::vec3(1.0, 0.0, 0.0),
glm::vec3(1.0, 0.0, 1.0),
glm::vec3(0.0, 0.0, 1.0),
glm::vec3(0.0, 0.0, 0.0)
},
// Top
{
glm::vec3(0.0, 1.0, 0.0),
glm::vec3(0.0, 1.0, 1.0),
glm::vec3(1.0, 1.0, 1.0),
glm::vec3(1.0, 1.0, 0.0)
},
// Left
{
glm::vec3(0.0, 0.0, 1.0),
glm::vec3(0.0, 1.0, 1.0),
glm::vec3(0.0, 1.0, 0.0),
glm::vec3(0.0, 0.0, 0.0)
},
// Right
{
glm::vec3(1.0, 0.0, 0.0),
glm::vec3(1.0, 1.0, 0.0),
glm::vec3(1.0, 1.0, 1.0),
glm::vec3(1.0, 0.0, 1.0)
},
// Back
{
glm::vec3(1.0, 0.0, 1.0),
glm::vec3(1.0, 1.0, 1.0),
glm::vec3(0.0, 1.0, 1.0),
glm::vec3(0.0, 0.0, 1.0)
},
// Front
{
glm::vec3(0.0, 0.0,0.0),
glm::vec3(0.0, 1.0,0.0),
glm::vec3(1.0, 1.0,0.0),
glm::vec3(1.0, 0.0,0.0)
}
};
Chunk::Chunk(Planet* planet, class PlanetFace* face, int x, int y, int z) :
m_planet(planet),
m_planetFace(face),
m_cx(x),
m_cy(y),
m_cz(z),
m_dirty(false),
m_active(true)
{
}
Chunk::~Chunk()
{
// Delete the buffers
deleteBuffers();
// Delete the cells
for (int i = 0; i < CHUNK_SIZE; ++i)
{
for (int j = 0; j < CHUNK_SIZE; ++j)
{
delete [] m_cells[i][j];
}
delete [] m_cells[i];
}
delete [] m_cells;
}
void Chunk::unload()
{
m_active = false;
// Make space in memory
m_vertices.clear();
deleteBuffers();
// Next time the chunk loads, we'll have to regenerate it.
m_dirty = true;
}
void Chunk::load()
{
m_active = true;
}
void Chunk::generate()
{
// Populate cells with dummy data
m_cells = new Cell**[CHUNK_SIZE];
for(int i = 0; i < CHUNK_SIZE; i++)
{
m_cells[i] = new Cell*[CHUNK_SIZE];
for(int j = 0; j < CHUNK_SIZE; j++)
{
m_cells[i][j] = new Cell[CHUNK_SIZE];
}
}
m_generated = true;
m_dirty = true;
}
void Chunk::updateFlags()
{
// Figure out if we are a completely empty chunk
//if(numVerts == 0 && numTriangles == 0)
//{
// m_emptyChunk = true;
//}
//m_emptyChunk = false;
}
void Chunk::draw(Camera* camera, Shader* shader)
{
if (!m_active || !m_vao || !m_vbo)
return;
shader->setBuffers(m_vao, m_vbo, 0);
shader->use();
m_model = glm::translate(glm::mat4(1.0f), this->getAbsolutePosition()) * m_planetFace->getOrientation();
camera->shaderViewProjection(*shader);
shader->setUniform("modelMatrix", m_model);
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
}
void Chunk::formFace(std::vector<Vertex> &vertices, const glm::vec3 &position, CellFace face)
{
// Calculate positions in mesh
auto P = [&](const glm::vec3& p) {
const glm::vec3 pp = (position + p);
return pp;
};
// Get the vertices of the selected face
const glm::vec3 pos[4] = {
P(FACE_VERTEX[face][0]), P(FACE_VERTEX[face][1]),
P(FACE_VERTEX[face][2]), P(FACE_VERTEX[face][3]),
};
// Calculate normals
glm::vec3 normal = glm::cross(pos[2] - pos[0], pos[3] - pos[1]);
// Construct face from triangles
vertices.push_back({pos[0], normal, {0.0, 1.0}});
vertices.push_back({pos[1], normal, {0.0, 0.0}});
vertices.push_back({pos[2], normal, {1.0, 0.0}});
vertices.push_back({pos[0], normal, {0.0, 1.0}});
vertices.push_back({pos[2], normal, {1.0, 0.0}});
vertices.push_back({pos[3], normal, {1.0, 1.0}});
}
void Chunk::rebuildMesh()
{
// Default visibility of a face
const bool faceDefault = true;
// Don't update the chunk again until a change has occured
m_dirty = false;
// Clear previous vertices
m_vertices.clear();
// Determine which cells should have which faces drawn
for (int x = 0; x < CHUNK_SIZE; x++)
{
for (int y = 0; y < CHUNK_SIZE; y++)
{
for (int z = 0; z < CHUNK_SIZE; z++)
{
if(m_cells[x][y][z].isSolid() == false)
{
continue;
}
bool faceLeft = faceDefault;
if(x > 0)
faceLeft = !m_cells[x-1][y][z].isSolid();
bool faceRight = faceDefault;
if(x < CHUNK_SIZE - 1)
faceRight = !m_cells[x+1][y][z].isSolid();
bool faceBottom = faceDefault;
if(y > 0)
faceBottom = !m_cells[x][y-1][z].isSolid();
bool faceTop = faceDefault;
if(y < CHUNK_SIZE - 1)
faceTop = !m_cells[x][y+1][z].isSolid();
bool faceBack = faceDefault;
if(z > 0)
faceBack = !m_cells[x][y][z-1].isSolid();
bool faceFront = faceDefault;
if(z < CHUNK_SIZE - 1)
faceFront = !m_cells[x][y][z+1].isSolid();
glm::vec3 cellPos = glm::vec3(x, y, z);
if (faceBottom)
formFace(m_vertices, cellPos, CELL_FACE_BOTTOM);
if (faceTop)
formFace(m_vertices, cellPos, CELL_FACE_TOP);
if (faceLeft)
formFace(m_vertices, cellPos, CELL_FACE_LEFT);
if (faceRight)
formFace(m_vertices, cellPos, CELL_FACE_RIGHT);
if (faceFront)
formFace(m_vertices, cellPos, CELL_FACE_FRONT);
if (faceBack)
formFace(m_vertices, cellPos, CELL_FACE_BACK);
}
}
}
// Delete previous buffers
deleteBuffers();
m_emptyChunk = m_vertices.size() == 0;
if (m_emptyChunk)
return;
// Generate buffers
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * m_vertices.size(), &(m_vertices[0]), GL_STATIC_DRAW);
}
bool Chunk::isDetailedEnough(Camera* camera)
{
// TODO: Level of detail on mesh
return true;
}
void Chunk::deleteBuffers()
{
if (m_vbo)
glDeleteBuffers(1, &m_vbo);
if (m_vao)
glDeleteBuffers(1, &m_vao);
}
const glm::vec3 Chunk::getAbsolutePosition()
{
return getPosition() + m_planetFace->getPosition();
}

View File

@ -1,82 +0,0 @@
#ifndef __CHUNK_H__
#define __CHUNK_H__
#include "util/Common.h"
#include "planet/Planet.h"
#include "Camera.h"
#define CHUNK_SIZE 16
struct Vertex
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 uv;
};
struct Cell
{
GLuint internalId;
bool isSolid()
{
return true;
}
};
enum CellFace {
CELL_FACE_BOTTOM, CELL_FACE_TOP,
CELL_FACE_LEFT, CELL_FACE_RIGHT,
CELL_FACE_FRONT, CELL_FACE_BACK
};
class Chunk
{
public:
Chunk(Planet* planet, class PlanetFace* face, int x, int y, int z);
~Chunk();
void unload();
void load();
void generate();
void rebuildMesh();
inline const glm::vec3 getPosition() const { return glm::vec3(m_cx, m_cy, m_cz); }
const glm::vec3 getAbsolutePosition();
inline int getX() const { return m_cx; }
inline int getY() const { return m_cy; }
inline int getZ() const { return m_cz; }
inline bool isLoaded() const { return m_active; }
inline bool isRedrawRequired() const { return m_dirty; }
inline bool isGenerated() const { return m_generated; }
inline bool shouldRender() const { return !m_emptyChunk && m_active && m_generated; }
inline glm::mat4 getModelMatrix() const { return m_model; }
bool isDetailedEnough(Camera* camera);
void draw(Camera* camera, Shader* shader);
void updateFlags();
private:
void formFace(std::vector<Vertex> &vertices, const glm::vec3 &position, CellFace face);
void deleteBuffers();
Planet* m_planet;
class PlanetFace* m_planetFace;
glm::mat4 m_model;
bool m_dirty;
bool m_active;
bool m_generated;
bool m_emptyChunk;
int m_cx, m_cy, m_cz;
GLuint m_vao, m_vbo;
Cell*** m_cells;
std::vector<Vertex> m_vertices;
};
#endif // __CHUNK_H__

View File

@ -19,16 +19,16 @@ Planet::~Planet()
void Planet::draw(Camera* camera, Shader* shader)
{
//for (int i = 0; i < 6; i++)
//{
m_faces[FACE_TOP]->draw(camera, shader);
//}
for (int i = 0; i < 6; i++)
{
m_faces[i]->draw(camera, shader);
}
}
void Planet::tick(Camera* camera, GLfloat dtime)
{
//for (int i = 0; i < 6; i++)
//{
m_faces[FACE_TOP]->tick(camera, dtime);
//}
for (int i = 0; i < 6; i++)
{
m_faces[i]->tick(camera, dtime);
}
}

View File

@ -1,344 +1,196 @@
#include "planet/PlanetFace.h"
#include "planet/Planet.h"
const glm::vec3 FACE_NORMALS[6] = {
glm::vec3(0.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(-1.0f, 0.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, -1.0f),
glm::vec3(0.0f, 0.0f, 1.0f)
};
PlanetFaceNode::PlanetFaceNode(Planet* planet, PlanetFace* face, glm::vec3 position, const unsigned int level) :
m_planet(planet), m_planetFace(face), m_pos(position), m_level(level), m_generated(false), m_dirty(true)
{
glm::vec3 normal = face->getNormal();
m_left = glm::vec3(normal.y, normal.z, normal.x);
m_forward = glm::cross(normal, m_left);
if (level == 0)
{
float radius = m_planet->getRadius() / 2.0f;
m_pos = m_pos - (m_left * radius);
m_pos = m_pos - (m_forward * radius);
}
}
PlanetFaceNode::~PlanetFaceNode()
{
for (int i = 0; i < 4; i++)
{
delete m_children[i];
}
glDeleteBuffers(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
}
void PlanetFaceNode::tick(Camera* camera, GLfloat dtime)
{
}
void PlanetFaceNode::draw(Camera* camera, Shader* shader)
{
if (!m_generated)
return;
shader->setBuffers(m_vao, m_vbo, m_ebo);
shader->use();
camera->shaderViewProjection(*shader);
shader->setUniform("modelMatrix", glm::translate(glm::mat4(1.0f), this->getAbsolutePosition()));
glDrawElements(GL_TRIANGLES, m_indices, GL_UNSIGNED_INT, nullptr);
}
void PlanetFaceNode::generate()
{
if (m_generated)
return;
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
float divisionLevel = (float)pow(2.0, m_level);
float radius = m_planet->getRadius();
for (int i = 0; i < RESOLUTION; i++)
{
for (int j = 0; j < RESOLUTION; j++)
{
float iindex = i / (RESOLUTION - 1.0);
float jindex = j / (RESOLUTION - 1.0);
// From the left and forward vectors, we can calculate an oriented vertex
glm::vec3 iv = ((m_left * iindex) * radius) / divisionLevel;
glm::vec3 jv = ((m_forward * jindex) * radius) / divisionLevel;
// Add the scaled left and forward to the centered origin
glm::vec3 vertex = m_pos + (iv + jv);
// Normalize and multiply by radius to create a spherical mesh
glm::vec3 vertNormal = glm::normalize(vertex);
glm::vec3 pos = vertNormal * radius;
// Add
vertices.push_back({ pos, vertNormal, glm::vec2(j * (1.0 / RESOLUTION), i * (1.0 / RESOLUTION)) });
}
}
for (int gz = 0; gz < RESOLUTION - 1; gz++)
{
for (int gx = 0; gx < RESOLUTION - 1; gx++)
{
int topLeft = (gz * RESOLUTION) + gx;
int topRight = topLeft + 1;
int bottomLeft = ((gz + 1) * RESOLUTION) + gx;
int bottomRight = bottomLeft + 1;
indices.push_back(topLeft);
indices.push_back(topRight);
indices.push_back(bottomLeft);
indices.push_back(bottomLeft);
indices.push_back(topRight);
indices.push_back(bottomRight);
}
}
m_indices = indices.size();
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo);
glGenBuffers(1, &m_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * m_indices, &(indices[0]), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), &(vertices[0]), GL_STATIC_DRAW);
m_generated = true;
m_leaf = true;
}
void PlanetFaceNode::subdivide()
{
if (m_level == 4)
return;
int lv = m_level + 1;
float radius = m_planet->getRadius();
glm::vec3 stepLeft = m_left * (radius / (float)pow(2, lv));
glm::vec3 stepForward = m_forward * (radius / (float)pow(2, lv));
m_children[0] = new PlanetFaceNode(m_planet, m_planetFace, m_pos + stepForward, lv);
m_children[1] = new PlanetFaceNode(m_planet, m_planetFace, (m_pos + stepLeft) + stepForward, lv);
m_children[2] = new PlanetFaceNode(m_planet, m_planetFace, m_pos, lv);
m_children[3] = new PlanetFaceNode(m_planet, m_planetFace, (m_pos + stepLeft), lv);
m_leaf = false;
this->dispose();
}
void PlanetFaceNode::merge()
{
if (m_level == 0 && m_leaf)
return;
for (int i = 0; i < 4; i++)
{
m_children[i]->merge();
m_children[i]->dispose();
delete m_children[i];
}
m_leaf = true;
}
void PlanetFaceNode::dispose()
{
m_generated = false;
glDeleteBuffers(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
}
bool PlanetFaceNode::isLeaf()
{
return m_leaf;
}
PlanetFace::PlanetFace(Planet* planet, const unsigned int face) :
m_planet(planet), m_face(face), m_pos(glm::vec3(0.0f, 0.0f, 0.0f))
m_planet(planet), m_face(face)
{
// Set face normal depending on face
switch (m_face)
{
case Face::FACE_BOTTOM:
m_normal = glm::vec3(0.0f, -1.0f, 0.0f);
break;
case Face::FACE_TOP:
m_normal = glm::vec3(0.0f, 1.0f, 0.0f);
break;
case Face::FACE_LEFT:
m_normal = glm::vec3(-1.0f, 0.0f, 0.0f);
break;
case Face::FACE_RIGHT:
m_normal = glm::vec3(1.0f, 0.0f, 0.0f);
break;
case Face::FACE_FRONT:
m_normal = glm::vec3(0.0f, 0.0f, -1.0f);
break;
case Face::FACE_BACK:
m_normal = glm::vec3(0.0f, 0.0f, 1.0f);
break;
}
m_chunks = new ChunkManager(this, planet->getRadius());
if (m_face < 2)
m_orientation = glm::rotate(glm::mat4(1.0f), (float)((face == FACE_BOTTOM ? 0.5 : -0.5) * M_PI),
glm::vec3(0.0f, 1.0f, 0.0f));
else
m_orientation = glm::rotate(glm::mat4(1.0f), (float)(face * -0.5 * M_PI), glm::vec3(1.0f, 0.0f, 0.0f));
m_normal = FACE_NORMALS[m_face];
m_planetFace = new PlanetFaceNode(planet, this, m_normal * (m_planet->getRadius() / 2.0f), 0);
m_planetFace->generate();
}
PlanetFace::~PlanetFace()
{
delete m_planetFace;
}
void PlanetFace::draw(Camera* camera, Shader* shader)
{
if (m_chunks)
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
m_chunks->render(camera, shader);
glDisable(GL_CULL_FACE);
}
m_planetFace->draw(camera, shader);
}
void PlanetFace::tick(Camera* camera, GLfloat dtime)
{
if (m_chunks)
{
m_chunks->update(camera, dtime);
}
}
// ******** //
// CHUNKS //
// ******** //
ChunkManager::ChunkManager(PlanetFace* face, GLuint chunkCount) : m_face(face)
{
m_forceVisibilityUpdate = true;
for (int x = 0; x < (int)chunkCount; x++)
{
for (int y = 0; y < (int)chunkCount; y++)
{
for (int z = 0; z < (int)chunkCount; z++)
{
m_chunks.push_back(new Chunk(m_face->getPlanet(), m_face, x * CHUNK_SIZE, y * CHUNK_SIZE, z * CHUNK_SIZE));
}
}
}
}
ChunkManager::~ChunkManager()
{
for(auto iterator = m_chunks.begin(); iterator != m_chunks.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
delete pChunk;
}
}
void ChunkManager::update(Camera* camera, GLfloat dtime)
{
updateUnload();
updateLoad();
updateRebuild();
updateGenerate();
updateFlags();
updateVisibility(camera);
updateRender(camera);
}
Chunk* ChunkManager::getChunk(int x, int y, int z)
{
for(auto iterator = m_chunks.begin(); iterator != m_chunks.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
if (pChunk->getX() == x && pChunk->getY() == y && pChunk->getZ() == z)
return pChunk;
}
return NULL;
}
void ChunkManager::updateUnload()
{
// Unload any chunks
for(auto iterator = m_chunkUnloadQueue.begin(); iterator != m_chunkUnloadQueue.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
if(pChunk->isLoaded())
{
pChunk->unload();
m_forceVisibilityUpdate = true;
}
}
// Clear the unload list (every frame)
m_chunkUnloadQueue.clear();
}
void ChunkManager::updateLoad()
{
int lNumOfChunksLoaded = 0;
for(auto iterator = m_chunkLoadQueue.begin(); iterator != m_chunkLoadQueue.end() &&
(lNumOfChunksLoaded != ASYNC_NUM_CHUNKS_PER_FRAME); ++iterator)
{
Chunk* pChunk = (*iterator);
if(pChunk->isLoaded() == false)
{
if(lNumOfChunksLoaded != ASYNC_NUM_CHUNKS_PER_FRAME)
{
pChunk->load();
// Increase the chunks loaded count
lNumOfChunksLoaded++;
m_forceVisibilityUpdate = true;
}
}
}
// Clear the load list (every frame)
m_chunkLoadQueue.clear();
}
void ChunkManager::updateRebuild()
{
// Rebuild any chunks that are in the rebuild chunk list
int lNumRebuiltChunkThisFrame = 0;
for(auto iterator = m_chunkRebuildQueue.begin(); iterator != m_chunkRebuildQueue.end() &&
(lNumRebuiltChunkThisFrame != ASYNC_NUM_CHUNKS_PER_FRAME); ++iterator)
{
Chunk* pChunk = (*iterator);
if(pChunk->isLoaded() && pChunk->isGenerated())
{
if(lNumRebuiltChunkThisFrame != ASYNC_NUM_CHUNKS_PER_FRAME)
{
pChunk->rebuildMesh();
// If we rebuild a chunk, add it to the list of chunks that need their render flags updated
// since we might now be empty or surrounded
m_chunkFlagsQueue.push_back(pChunk);
// Also add our neighbours since they might now be surrounded too (If we have neighbours)
Chunk* pChunkXMinus = getChunk(pChunk->getX()-1, pChunk->getY(), pChunk->getZ());
Chunk* pChunkXPlus = getChunk(pChunk->getX()+1, pChunk->getY(), pChunk->getZ());
Chunk* pChunkYMinus = getChunk(pChunk->getX(), pChunk->getY()-1, pChunk->getZ());
Chunk* pChunkYPlus = getChunk(pChunk->getX(), pChunk->getY()+1, pChunk->getZ());
Chunk* pChunkZMinus = getChunk(pChunk->getX(), pChunk->getY(), pChunk->getZ()-1);
Chunk* pChunkZPlus = getChunk(pChunk->getX(), pChunk->getY(), pChunk->getZ()+1);
if(pChunkXMinus != NULL)
m_chunkFlagsQueue.push_back(pChunkXMinus);
if(pChunkXPlus != NULL)
m_chunkFlagsQueue.push_back(pChunkXPlus);
if(pChunkYMinus != NULL)
m_chunkFlagsQueue.push_back(pChunkYMinus);
if(pChunkYPlus != NULL)
m_chunkFlagsQueue.push_back(pChunkYPlus);
if(pChunkZMinus != NULL)
m_chunkFlagsQueue.push_back(pChunkZMinus);
if(pChunkZPlus != NULL)
m_chunkFlagsQueue.push_back(pChunkZPlus);
// Only rebuild a certain number of chunks per frame
lNumRebuiltChunkThisFrame++;
m_forceVisibilityUpdate = true;
}
}
}
// Clear the rebuild list
m_chunkRebuildQueue.clear();
}
void ChunkManager::updateFlags()
{
for(auto iterator = m_chunkFlagsQueue.begin(); iterator != m_chunkFlagsQueue.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
pChunk->updateFlags();
}
m_chunkFlagsQueue.clear();
}
void ChunkManager::updateGenerate()
{
// Generate any chunks that have not already been generated
for(auto iterator = m_chunkGenerateQueue.begin(); iterator != m_chunkGenerateQueue.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
if(pChunk->isLoaded() && pChunk->isGenerated() == false)
{
pChunk->generate();
if(pChunk->isGenerated())
{
// Only force the visibility update if we actually generate the chunk, some chunks wait in the pre-generate stage...
m_forceVisibilityUpdate = true;
}
}
}
// Clear the generate list (every frame)
m_chunkGenerateQueue.clear();
}
void ChunkManager::updateVisibility(Camera* camera)
{
m_forceVisibilityUpdate = false;
m_chunksVisible.clear();
for(auto iterator = m_chunks.begin(); iterator != m_chunks.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
// TODO: Temporary distance limit
if (glm::abs(glm::length(camera->getPosition() - pChunk->getAbsolutePosition())) > 64.0f)
{
if (pChunk->isLoaded())
{
m_chunkUnloadQueue.push_back(pChunk);
continue;
}
continue;
}
else
{
if (!pChunk->isLoaded())
{
m_chunkLoadQueue.push_back(pChunk);
continue;
}
}
// Generate chunk
if (!pChunk->isGenerated())
{
m_chunkGenerateQueue.push_back(pChunk);
continue;
}
if (pChunk->isRedrawRequired() || !pChunk->isDetailedEnough(camera))
{
m_chunkRebuildQueue.push_back(pChunk);
continue;
}
m_chunksVisible.push_back(pChunk);
}
}
void ChunkManager::updateRender(Camera* camera)
{
// Clear the render list each frame BEFORE we do our tests to see what chunks should be rendered
m_chunkRenderQueue.clear();
for(auto iterator = m_chunksVisible.begin(); iterator != m_chunksVisible.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
if(pChunk != NULL)
{
if(pChunk->isLoaded() && pChunk->isGenerated())
{
if(pChunk->shouldRender()) // Early flags check so we don't always have to do the frustum check...
{
// TODO: fix frustum culling
//glm::vec3 pos = pChunk->getAbsolutePosition();
//glm::mat4 model = glm::translate(glm::mat4(1.0f), pos);
//camera->updateFrustum(model);
//if(camera->frustumContainsBox(glm::vec3(0.0f), glm::vec3((float)CHUNK_SIZE / 2)) > 0)
//{
m_chunkRenderQueue.push_back(pChunk);
//}
}
}
}
}
}
void ChunkManager::render(Camera* camera, Shader* shader)
{
// Render only the chunks that should be rendered
for(auto iterator = m_chunkRenderQueue.begin(); iterator != m_chunkRenderQueue.end(); ++iterator)
{
Chunk* pChunk = (*iterator);
pChunk->draw(camera, shader);
}
m_planetFace->tick(camera, dtime);
}

View File

@ -2,56 +2,66 @@
#define __PLANETFACE_H__
#include "util/Common.h"
#include "planet/Chunk.h"
#include "planet/Planet.h"
#include "Shader.h"
#include "Camera.h"
#define ASYNC_NUM_CHUNKS_PER_FRAME 8
#define RESOLUTION 128
enum Face {
enum Face
{
FACE_BOTTOM, FACE_TOP,
FACE_LEFT, FACE_RIGHT,
FACE_FRONT, FACE_BACK
};
struct Vertex
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 uv;
};
class Planet;
class PlanetFace;
// PlanetFace Chunk Manager
class ChunkManager
class PlanetFaceNode
{
public:
ChunkManager(PlanetFace* face, GLuint chunkCount);
~ChunkManager();
PlanetFaceNode(Planet* planet, PlanetFace* face, glm::vec3 position, const unsigned int level);
~PlanetFaceNode();
void update(Camera* camera, GLfloat dtime);
Chunk* getChunk(int x, int y, int z);
void tick(Camera* camera, GLfloat dtime);
void draw(Camera* camera, Shader* shader);
void render(Camera* camera, Shader* shader);
void generate();
void subdivide();
void merge();
void dispose();
bool isLeaf();
inline Planet* getPlanet() const { return m_planet; }
inline PlanetFace* getPlanetFace() const { return m_planetFace; }
inline glm::vec3 getAbsolutePosition() const { return m_planet->getPosition() + m_pos; }
private:
void updateUnload();
void updateLoad();
void updateGenerate();
void updateRebuild();
void updateFlags();
void updateVisibility(Camera* camera);
void updateRender(Camera* camera);
Planet* m_planet;
PlanetFace* m_planetFace;
std::vector<Chunk*> m_chunks;
std::vector<Chunk*> m_chunksVisible;
PlanetFaceNode* m_parent;
PlanetFaceNode* m_children[4];
// Queues
std::vector<Chunk*> m_chunkUnloadQueue;
std::vector<Chunk*> m_chunkLoadQueue;
std::vector<Chunk*> m_chunkGenerateQueue;
std::vector<Chunk*> m_chunkRebuildQueue;
std::vector<Chunk*> m_chunkRenderQueue;
std::vector<Chunk*> m_chunkFlagsQueue;
unsigned int m_level;
bool m_dirty;
bool m_generated;
bool m_leaf;
PlanetFace* m_face;
GLuint m_ebo, m_vao, m_vbo;
int m_indices;
int m_chunksLoaded = 0;
bool m_forceVisibilityUpdate;
glm::vec3 m_pos;
glm::vec3 m_left;
glm::vec3 m_forward;
};
class PlanetFace
@ -65,17 +75,13 @@ class PlanetFace
inline Planet* getPlanet() const { return m_planet; }
inline const glm::vec3 getPosition() const { return m_planet->getPosition() + m_pos; }
inline const glm::mat4 getOrientation() const { return m_orientation; }
inline const glm::vec3 getNormal() const { return m_normal; }
private:
Planet* m_planet;
unsigned int m_face;
glm::vec3 m_normal;
glm::vec3 m_pos;
ChunkManager* m_chunks;
glm::mat4 m_orientation;
PlanetFaceNode* m_planetFace;
};
#endif // __PLANETFACE_H__