#include "PlanetIndexBuffer.h" 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, detailTop); buildEdge(triangleFans, RIGHT, detailRight); buildEdge(triangleFans, BOTTOM, detailBottom); buildEdge(triangleFans, LEFT, detailLeft); // 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() { glDeleteBuffers(1, &m_ibo); } 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; } } // 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)); }