339 lines
7.7 KiB
C++
339 lines
7.7 KiB
C++
#include "planet/PlanetFace.h"
|
|
#include "planet/Planet.h"
|
|
|
|
PlanetFace::PlanetFace(Planet* planet, const unsigned int face) :
|
|
m_planet(planet), m_face(face), m_pos(glm::vec3(0.0f, 0.0f, 0.0f))
|
|
{
|
|
// 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());
|
|
}
|
|
|
|
PlanetFace::~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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|