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