267 lines
5.4 KiB
C++
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();
|
|
}
|