voxspatium/src/planet/Chunk.cpp

267 lines
5.4 KiB
C++

#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();
}