diff --git a/src/icosphere.cpp b/src/icosphere.cpp index 7eefb43..ce6e9c8 100644 --- a/src/icosphere.cpp +++ b/src/icosphere.cpp @@ -1,32 +1,46 @@ #include "icosphere.hpp" #include +#include Icosphere::Icosphere(int subdivisions) { + VertexList vertices = _isocahedronVertices; + TriangleList triangles = _isocahedronTriangles; + for (int i = 0; i < subdivisions; i++) + { + triangles = subdivide(vertices, triangles); + } + std::cout << + "subdivisions: " << subdivisions << + " vertices: " << vertices.size() << + " triangles: " << triangles.size() << std::endl; + glGenVertexArrays(1, &_vao); glGenBuffers(1, &_vbo); glGenBuffers(1, &_ebo); glBindVertexArray(_vao); - for (const auto& v : _isocahedronVertices) + for (const auto& v : vertices) { _vertices.push_back(v[0]); _vertices.push_back(v[1]); _vertices.push_back(v[2]); } glBindBuffer(GL_ARRAY_BUFFER, _vbo); - glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float), &_vertices[0], GL_STATIC_DRAW); + size_t vboBufferSize = _vertices.size() * sizeof(float); + glBufferData(GL_ARRAY_BUFFER, vboBufferSize, &_vertices[0], GL_STATIC_DRAW); - for (const auto& tri : _isocahedronTriangles) + for (const auto& tri : triangles) { _indices.push_back(tri.vertex[0]); _indices.push_back(tri.vertex[1]); _indices.push_back(tri.vertex[2]); } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size() * sizeof(unsigned int), &_indices[0], GL_STATIC_DRAW); + size_t egoBufferSize = _indices.size() * sizeof(unsigned int); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, egoBufferSize, &_indices[0], GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); @@ -36,6 +50,59 @@ Icosphere::Icosphere(int subdivisions) glBindVertexArray(0); } +int Icosphere::vertexForEdge(Lookup& lookup, VertexList& vertices, int first, int second) +{ + Lookup::key_type key(first, second); + // Normalize edge directions so that we don't store edges twice + if (key.first > key.second) + { + std::swap(key.first, key.second); + } + + // .insert returns a pair with a pointer to the newly-inserted (or already + // existing) element in the lookup as the first element and a boolean + // indicating a successful new insertion as the second. + auto inserted = lookup.insert({key, vertices.size()}); + + // If the insertion was successful - i.e this is a newly inserted element + if (inserted.second) + { + // Two vectors determined by two existing points + auto& edge0 = vertices[first]; + auto& edge1 = vertices[second]; + // Combine and normalize the vectors to get the halfway point on the + // unit sphere. + auto point = normalize(edge0 + edge1); + vertices.push_back(point); + } + + return inserted.first->second; +} + +Icosphere::TriangleList Icosphere::subdivide(VertexList& vertices, TriangleList triangles) +{ + Lookup lookup; + TriangleList result; + + for (auto&& triangle : triangles) + { + std::array mid; + for (int edge = 0; edge < 3; edge++) + { + mid[edge] = vertexForEdge(lookup, vertices, + triangle.vertex[edge], triangle.vertex[(edge + 1) % 3]); + } + + // Create four new triangles from the original triangle + result.push_back({triangle.vertex[0], mid[0], mid[2]}); + result.push_back({triangle.vertex[1], mid[1], mid[0]}); + result.push_back({triangle.vertex[2], mid[2], mid[1]}); + result.push_back({mid[0], mid[1], mid[2]}); + } + + return result; +} + void Icosphere::render() { glBindVertexArray(_vao); diff --git a/src/icosphere.hpp b/src/icosphere.hpp index c71aaa0..908aee6 100644 --- a/src/icosphere.hpp +++ b/src/icosphere.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "glm/glm.hpp" @@ -22,12 +23,12 @@ private: std::vector _vertices; std::vector _indices; - struct IcoTriangle + struct Triangle { - unsigned int vertex[3]; + int vertex[3]; }; - using IcoTriangleList = std::vector; + using TriangleList = std::vector; using VertexList = std::vector; const float X=.525731112119133606f; @@ -41,11 +42,16 @@ private: {Z,X,N}, {-Z,X, N}, {Z,-X,N}, {-Z,-X, N} }; - const IcoTriangleList _isocahedronTriangles = + const TriangleList _isocahedronTriangles = { {0,4,1},{0,9,4},{9,5,4},{4,5,8},{4,8,1}, {8,10,1},{8,3,10},{5,3,8},{5,2,3},{2,7,3}, {7,10,3},{7,6,10},{7,11,6},{11,0,6},{0,1,6}, {6,1,10},{9,0,11},{9,11,2},{9,2,5},{7,2,11} }; + + using Lookup = std::map, int>; + + int vertexForEdge(Lookup& lookup, VertexList& vertices, int first, int second); + TriangleList subdivide(VertexList& vertices, TriangleList triangles); }; \ No newline at end of file