diff --git a/src/Application.cpp b/src/Application.cpp index 628e559..c70b150 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -205,7 +205,7 @@ void Application::run() // TEST CODE glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + glCullFace(GL_FRONT); if (!m_pauseLod) pl->tick(m_camera, deltaTime); diff --git a/src/Camera.cpp b/src/Camera.cpp index 023c3c7..eba834c 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -204,22 +204,23 @@ void Camera::processMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean co void Camera::processMouseScroll(GLfloat yoffset) { - if (m_zoom >= 44.0f && m_zoom <= 45.0f) - { - m_zoom -= yoffset; - } + // if (m_zoom >= 44.0f && m_zoom <= 45.0f) + // { + // m_zoom -= yoffset; + // } - if (m_zoom <= 44.0f) - { - m_zoom = 44.0f; - } + // if (m_zoom <= 44.0f) + // { + // m_zoom = 44.0f; + // } - if (m_zoom >= 45.0f) - { - m_zoom = 45.0f; - } + // if (m_zoom >= 45.0f) + // { + // m_zoom = 45.0f; + // } - updateProjection(); + // updateProjection(); + m_movementSpeed += yoffset * 50.0f; } void Camera::updateProjection(void) diff --git a/src/planet/Planet.cpp b/src/planet/Planet.cpp index 3562273..bdea6c4 100644 --- a/src/planet/Planet.cpp +++ b/src/planet/Planet.cpp @@ -2,9 +2,22 @@ #include "planet/PlanetFace.h" Planet::Planet(glm::vec3 position, float radius, PlanetNoiseParams &noiseParams) : - m_position(position), m_radius(radius), m_noise(noiseParams.frequency, noiseParams.amplitude, noiseParams.lacunarity, noiseParams.persistence), - m_ibuffers(new PlanetIndexBuffer(15)) + m_position(position), m_radius(radius), m_noise(noiseParams.frequency, noiseParams.amplitude, noiseParams.lacunarity, noiseParams.persistence) { + for (unsigned int a = 0; a <= 4; a++) + { + for (unsigned int b = 0; b <= 4; b++) + { + for (unsigned int c = 0; c <= 4; c++) + { + for (unsigned int d = 0; d <= 4; d++) + { + m_ibuffers[a][b][c][d] = new PlanetIndexBuffer(16, a, b, c, d); + } + } + } + } + for (int i = 0; i < 6; i++) { m_faces[i] = new PlanetFace(this, i); @@ -18,7 +31,21 @@ Planet::~Planet() { delete m_faces[i]; } - delete m_ibuffers; + + for (unsigned int a = 0; a <= 4; a++) + { + for (unsigned int b = 0; b <= 4; b++) + { + for (unsigned int c = 0; c <= 4; c++) + { + for (unsigned int d = 0; d <= 4; d++) + { + delete m_ibuffers[a][b][c][d]; + m_ibuffers[a][b][c][d] = 0; + } + } + } + } } void Planet::draw(Camera* camera, Shader* shader) @@ -60,3 +87,7 @@ glm::mat4 Planet::getTransformation() newMat = glm::translate(newMat, m_position); return newMat; } + +PlanetIndexBuffer* Planet::getIndexBuffer(const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft) { + return m_ibuffers[detailTop][detailRight][detailBottom][detailLeft]; +} diff --git a/src/planet/Planet.h b/src/planet/Planet.h index ebfef81..68a299c 100644 --- a/src/planet/Planet.h +++ b/src/planet/Planet.h @@ -33,14 +33,14 @@ class Planet void draw(Camera* camera, Shader* shader); inline SimplexNoise& getNoise() { return m_noise; } - inline PlanetIndexBuffer* getBuffers() { return m_ibuffers; } inline PlanetFace* getFace(const unsigned int face) { return m_faces[face]; } + PlanetIndexBuffer* getIndexBuffer(const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft); glm::mat4 getTransformation(); private: void connectFaces(); - PlanetIndexBuffer* m_ibuffers; + PlanetIndexBuffer* m_ibuffers[5][5][5][5]; SimplexNoise m_noise; glm::vec3 m_position; float m_radius; diff --git a/src/planet/PlanetFace.cpp b/src/planet/PlanetFace.cpp index 7cd815f..22c0090 100644 --- a/src/planet/PlanetFace.cpp +++ b/src/planet/PlanetFace.cpp @@ -236,6 +236,12 @@ void PlanetFaceNode::updateNeighborDetailDifferences(const unsigned int side) } } +// Returns the neighbor detail (depth) difference [0,MAX_DETAIL_DIFFERENCE] +unsigned int PlanetFaceNode::getNeighborDetailDifference(const unsigned int side) const +{ + return neighborDetailDifferences[side]; +} + void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) { // TODO: based on planet transform @@ -259,12 +265,6 @@ void PlanetFaceNode::tick(Camera* camera, GLfloat dtime) } } -void PlanetFaceNode::setIndexBuffer(PlanetBufferIndex buf) { - PIB* indx = m_planetFace->getPlanet()->getBuffers()->getBuffer(buf); - m_ebo = indx->ebo; - m_indices = indx->indices.size(); -} - void PlanetFaceNode::draw(Camera* camera, Shader* shader) { // TODO: occlusion culling @@ -280,49 +280,20 @@ void PlanetFaceNode::draw(Camera* camera, Shader* shader) if (!m_generated) return; - if (neighborDetailDifferences[TOP] == 1) { - if (neighborDetailDifferences[RIGHT] == 1) { - setIndexBuffer(FixTR); - } else if (neighborDetailDifferences[LEFT] == 1) { - setIndexBuffer(FixTL); - } else { - setIndexBuffer(FixT); - } - } else if (neighborDetailDifferences[BOTTOM] == 1) { - if (neighborDetailDifferences[RIGHT] == 1) { - setIndexBuffer(FixBR); - } else if (neighborDetailDifferences[LEFT] == 1) { - setIndexBuffer(FixBL); - } else { - setIndexBuffer(FixB); - } - } else if (neighborDetailDifferences[RIGHT] == 1) { - if (neighborDetailDifferences[BOTTOM] == 1) { - setIndexBuffer(FixBR); - } else if (neighborDetailDifferences[TOP] == 1) { - setIndexBuffer(FixTR); - } else { - setIndexBuffer(FixR); - } - } else if (neighborDetailDifferences[LEFT] == 1) { - if (neighborDetailDifferences[BOTTOM] == 1) { - setIndexBuffer(FixBL); - } else if (neighborDetailDifferences[TOP] == 1) { - setIndexBuffer(FixTL); - } else { - setIndexBuffer(FixL); - } - } else { - setIndexBuffer(Base); - } + PlanetIndexBuffer* buffers = m_planetFace->getPlanet()->getIndexBuffer( + getNeighborDetailDifference(TOP), + getNeighborDetailDifference(RIGHT), + getNeighborDetailDifference(BOTTOM), + getNeighborDetailDifference(LEFT) + ); - shader->setBuffers(m_vao, m_vbo, m_ebo); + shader->setBuffers(m_vao, m_vbo, buffers->getIbo()); shader->use(); camera->shaderViewProjection(*shader); shader->setUniform("modelMatrix", m_planetFace->getPlanet()->getTransformation()); - glDrawElements(GL_TRIANGLES, m_indices, GL_UNSIGNED_INT, nullptr); + glDrawElements(GL_TRIANGLES, buffers->getVertexCount(), GL_UNSIGNED_SHORT, nullptr); } void PlanetFaceNode::generate() @@ -405,8 +376,6 @@ void PlanetFaceNode::generate() m_center = boundingSphereCenterF; m_radius = boundingSphereRadiusF; - std::cout << m_radius << std::endl; - m_generated = true; } @@ -484,7 +453,7 @@ PlanetFace::PlanetFace(Planet* planet, const unsigned int face) : m_planet(planet), m_face(face) { m_normal = FACE_NORMALS[m_face]; - m_lod = new PlanetFaceNode(this, 0, m_normal, face); + m_lod = new PlanetFaceNode(this, 0, m_normal, 0); } PlanetFace::~PlanetFace() @@ -505,8 +474,9 @@ void PlanetFace::tick(Camera* camera, GLfloat dtime) void PlanetFace::connect(const unsigned int side, PlanetFace* face) { - if (m_lod && face->getLODRoot()) + if (m_lod && face->getLODRoot()) { m_lod->setNeighbor(side, face->getLODRoot()); + } } bool PlanetFace::hasSplitsLeft() diff --git a/src/planet/PlanetFace.h b/src/planet/PlanetFace.h index f31b06d..b65c187 100644 --- a/src/planet/PlanetFace.h +++ b/src/planet/PlanetFace.h @@ -6,7 +6,7 @@ #include "Shader.h" #include "Camera.h" -#define RESOLUTION 15 +#define RESOLUTION 17 enum Face { @@ -24,12 +24,6 @@ enum Quadrant BOTTOM_RIGHT, BOTTOM_LEFT }; -enum Direction -{ - TOP, RIGHT, - BOTTOM, LEFT, -}; - const unsigned int MAX_SPLITS_PER_UPDATE = 2; #define MIRROR(s) (((s) + 2) % 4) @@ -74,8 +68,6 @@ class PlanetFaceNode bool merge(); void dispose(); - void setIndexBuffer(PlanetBufferIndex buf); - void findNeighbor(const unsigned int side); void getNeighbor(const unsigned int side); void updateNeighborDetailDifferences(const unsigned int side); diff --git a/src/planet/PlanetIndexBuffer.cpp b/src/planet/PlanetIndexBuffer.cpp index 75c7e43..b6b6b19 100644 --- a/src/planet/PlanetIndexBuffer.cpp +++ b/src/planet/PlanetIndexBuffer.cpp @@ -1,145 +1,179 @@ #include "PlanetIndexBuffer.h" -PlanetIndexBuffer::PlanetIndexBuffer(unsigned int resolution) : m_resolution(resolution) { - createBuffer(PlanetBufferIndex::Base); - createBuffer(PlanetBufferIndex::FixT, false, false, true, false); - createBuffer(PlanetBufferIndex::FixR, true, false, false, false); - createBuffer(PlanetBufferIndex::FixB, false, true, false, false); - createBuffer(PlanetBufferIndex::FixL, false, false, false, true); - createBuffer(PlanetBufferIndex::FixTL, false, false, true, true); - createBuffer(PlanetBufferIndex::FixTR, true, false, true, false); - createBuffer(PlanetBufferIndex::FixBR, true, true, false, false); - createBuffer(PlanetBufferIndex::FixBL, false, true, false, true); +PlanetIndexBuffer::PlanetIndexBuffer( + unsigned int resolution, + const unsigned int detailTop, + const unsigned int detailRight, + const unsigned int detailBottom, + const unsigned int detailLeft +) : m_resolution(resolution) { + TriangleFanList triangleFans; + + // Build the patch body (without edges) + for (unsigned int x = 2; x < m_resolution - 1; x += 2) + { + for (unsigned int y = 2; y < m_resolution - 1; y += 2) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, x, y); + addTriangleFanVertex(triangleFans, x + 1, y + 1); + addTriangleFanVertex(triangleFans, x, y + 1); + addTriangleFanVertex(triangleFans, x - 1, y + 1); + addTriangleFanVertex(triangleFans, x - 1, y); + addTriangleFanVertex(triangleFans, x - 1, y - 1); + addTriangleFanVertex(triangleFans, x, y - 1); + addTriangleFanVertex(triangleFans, x + 1, y - 1); + addTriangleFanVertex(triangleFans, x + 1, y); + addTriangleFanVertex(triangleFans, x + 1, y + 1); + } + } + + // Build all four edges + buildEdge(triangleFans, TOP, detailLeft); + buildEdge(triangleFans, RIGHT, detailBottom); + buildEdge(triangleFans, BOTTOM, detailRight); + buildEdge(triangleFans, LEFT, detailTop); + + // Count the number of triangles and reserve three vertices per triangle + int triangleCount = 0; + for (unsigned int i = 0; i < triangleFans.size(); i++) + if (triangleFans[i].size() > 2) + triangleCount += triangleFans[i].size() - 2; + m_vertexCount = 3 * triangleCount; + + // Create an index array + GLushort *indexData = new GLushort[m_vertexCount]; + int n = 0; + for (unsigned int i = 0; i < triangleFans.size(); i++) + { + for (unsigned int j = 2; j < triangleFans[i].size(); j++) + { + indexData[n++] = triangleFans[i][0]; + indexData[n++] = triangleFans[i][j-1]; + indexData[n++] = triangleFans[i][j]; + } + } + + // Generate the index buffer object (IBO) + glGenBuffers(1, &m_ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * m_vertexCount, indexData, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // Delete unnecessary data + triangleFans.clear(); + delete[] indexData; } PlanetIndexBuffer::~PlanetIndexBuffer() { - for (int i = 0; i < 9; i++) { - if (m_buffers[i] == nullptr) continue; - glDeleteBuffers(1, &m_buffers[i]->ebo); - m_buffers[i]->indices.clear(); - delete m_buffers[i]; - } + glDeleteBuffers(1, &m_ibo); } -PIB* PlanetIndexBuffer::getBuffer(PlanetBufferIndex idx) { - return m_buffers[idx]; +void PlanetIndexBuffer::rotateIndices(unsigned int &x, unsigned int &y, const unsigned int rotation) +{ + // Change the indices to match the given rotation + switch (rotation) + { + case TOP: + default: + return; + case RIGHT: + std::swap(x, y); + y = m_resolution - y; + return; + case BOTTOM: + x = m_resolution - x; + y = m_resolution - y; + return; + case LEFT: + std::swap(x, y); + x = m_resolution - x; + return; + } } -void PlanetIndexBuffer::createBuffer(PlanetBufferIndex idx, bool fanTop, bool fanRight, bool fanLeft, bool fanBottom) { - PIB* buffer = new PIB(); - // Create indices for mesh - for (unsigned int gz = 0; gz < m_resolution - 1; gz++) - { - bool slantLeft = gz % 2 == 0; - for (unsigned int gx = 0; gx < m_resolution - 1; gx++) - { - unsigned int topLeft = (gz * m_resolution) + gx; - unsigned int topRight = topLeft + 1; - unsigned int bottomLeft = ((gz + 1) * m_resolution) + gx; - unsigned int bottomRight = bottomLeft + 1; - - bool uTri1 = true; - bool uTri2 = true; - unsigned int tri1[3]; - unsigned int tri2[3]; - - if (slantLeft) - { - tri1[0] = topLeft; - tri1[1] = bottomLeft; - tri1[2] = bottomRight; - tri2[0] = topLeft; - tri2[1] = bottomRight; - tri2[2] = topRight; - } - else - { - tri1[0] = topLeft; - tri1[1] = bottomLeft; - tri1[2] = topRight; - tri2[0] = bottomLeft; - tri2[1] = bottomRight; - tri2[2] = topRight; - } - - if (fanTop && gz == 0) - { - if (gx % 2 == 0) - { - tri2[0] = topLeft; - tri2[1] = bottomRight; - tri2[2] = topRight + 1; - } - else - { - uTri1 = false; - } - } - - if (fanRight && gx == m_resolution - 2) - { - if (gz % 2 == 0) - { - tri2[0] = topRight; - tri2[1] = bottomLeft; - tri2[2] = bottomRight + m_resolution; - } - else - { - uTri2 = false; - } - } - - if (fanBottom && gz == m_resolution - 2) - { - if (gx % 2 == 0) - { - tri2[0] = bottomLeft; - tri2[1] = bottomRight + 1; - tri2[2] = topRight; - } - else - { - uTri1 = false; - } - } - - if (fanLeft && gx == 0) - { - if (gz % 2 == 0) - { - tri1[0] = topLeft; - tri1[1] = bottomLeft + m_resolution; - tri1[2] = bottomRight; - } - else - { - uTri1 = false; - } - } - - if (uTri1) - { - buffer->indices.push_back(tri1[0]); - buffer->indices.push_back(tri1[1]); - buffer->indices.push_back(tri1[2]); - } - - if (uTri2) - { - buffer->indices.push_back(tri2[0]); - buffer->indices.push_back(tri2[1]); - buffer->indices.push_back(tri2[2]); - } - - slantLeft = !slantLeft; - } - } - - glGenBuffers(1, &(buffer->ebo)); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * buffer->indices.size(), &(buffer->indices[0]), GL_STATIC_DRAW); - - m_buffers[idx] = buffer; +// Creates and adds a triangle fan +void PlanetIndexBuffer::addTriangleFan(TriangleFanList &triangleFans) +{ + triangleFans.push_back(TriangleFan()); +} + +// adds a vertex index to the most recently added triangle fan +void PlanetIndexBuffer::addTriangleFanVertex(TriangleFanList &triangleFans, unsigned int x, unsigned int y, const unsigned int rotation) +{ + // Rotate and use the x and y indices + PlanetIndexBuffer::rotateIndices(x, y, rotation); + triangleFans.back().push_back(index1D(x,y)); +} + +void PlanetIndexBuffer::buildEdge(TriangleFanList &triangleFans, const unsigned int side, const unsigned int detail) +{ + // If detail difference is 0 (default case) or too high + if (detail == 0 || detail > 4) + { + for (unsigned int x = 0; x < m_resolution - 1; x += 2) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, x + 1, m_resolution - 1, side); + for (int d = -1; d <= 1; d++) + addTriangleFanVertex(triangleFans, x + 1 - d, m_resolution, side); + + if (x > 0) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, x, m_resolution, side); + for (int d = -1; d <= 1; d++) + addTriangleFanVertex(triangleFans, x + d, m_resolution - 1, side); + } + } + return; + } + + // Calculate step sizes; step = 2^detail + const int step = 1 << detail; + const int halfStep = step / 2; + + unsigned int x = 0; + for (x = 0; x < m_resolution; x += step) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, x, m_resolution, side); + addTriangleFanVertex(triangleFans, x + halfStep, m_resolution - 1, side); + addTriangleFanVertex(triangleFans, x + step, m_resolution, side); + + if (x > 0) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, x, m_resolution, side); + for (int d = -halfStep; d <= halfStep; d++) + addTriangleFanVertex(triangleFans, x + d, m_resolution - 1, side); + } + } + + if (step > 2) + { + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, 0, m_resolution, side); + for (int d = 1; d <= halfStep; d++) + addTriangleFanVertex(triangleFans, d, m_resolution - 1, side); + + addTriangleFan(triangleFans); + addTriangleFanVertex(triangleFans, m_resolution, m_resolution, side); + for (int d = -halfStep; d <= -1; d++) + addTriangleFanVertex(triangleFans, m_resolution + d, m_resolution - 1, side); + } +} + +GLsizei PlanetIndexBuffer::getVertexCount() const +{ + return m_vertexCount; +} + +GLuint PlanetIndexBuffer::getIbo() const +{ + return m_ibo; +} + +unsigned int PlanetIndexBuffer::index1D(const unsigned int x, const unsigned int y) { + return ((x) + (y) * (m_resolution + 1)); } diff --git a/src/planet/PlanetIndexBuffer.h b/src/planet/PlanetIndexBuffer.h index af128de..ce7f628 100644 --- a/src/planet/PlanetIndexBuffer.h +++ b/src/planet/PlanetIndexBuffer.h @@ -3,24 +3,37 @@ #include "util/Common.h" -struct PIB { - GLuint ebo; - std::vector indices; +enum Direction +{ + TOP, RIGHT, + BOTTOM, LEFT, }; -enum PlanetBufferIndex { - Base, FixT, FixR, FixB, FixL, FixTL, FixTR, FixBR, FixBL -}; + +typedef std::vector TriangleFan; +typedef std::vector TriangleFanList; class PlanetIndexBuffer { public: - PlanetIndexBuffer(unsigned int resolution); + PlanetIndexBuffer(unsigned int resolution, const unsigned int detailTop, const unsigned int detailRight, const unsigned int detailBottom, const unsigned int detailLeft); ~PlanetIndexBuffer(); - - PIB* getBuffer(PlanetBufferIndex idx); + + // Instance methods + GLsizei getVertexCount() const; + GLuint getIbo() const; private: - void createBuffer(PlanetBufferIndex idx, bool fanTop = false, bool fanRight = false, bool fanLeft = false, bool fanBottom = false); - PIB* m_buffers[9]; + void rotateIndices(unsigned int &x, unsigned int &y, const unsigned int rotation); + void addTriangleFan(TriangleFanList &triangleFans); + void addTriangleFanVertex(TriangleFanList &triangleFans, unsigned int x, unsigned int y, const unsigned int rotation = 0); + void buildEdge(TriangleFanList &triangleFans, const unsigned int side, const unsigned int detail = 0); + + // Instance variables + GLsizei m_vertexCount; + GLuint m_ibo; + + // TODO: move to utility + unsigned int index1D(const unsigned int x, const unsigned int y); + unsigned int m_resolution; };