+#include <stdio.h>
+#include "meshgen.h"
+#include "mesh.h"
+
+// ------ geosphere ------
+#define PHI 1.618034
+
+/* icosahedron points */
+static Vec3 icosa_pt[] = {
+ Vec3(PHI, 1, 0),
+ Vec3(-PHI, 1, 0),
+ Vec3(PHI, -1, 0),
+ Vec3(-PHI, -1, 0),
+ Vec3(1, 0, PHI),
+ Vec3(1, 0, -PHI),
+ Vec3(-1, 0, PHI),
+ Vec3(-1, 0, -PHI),
+ Vec3(0, PHI, 1),
+ Vec3(0, -PHI, 1),
+ Vec3(0, PHI, -1),
+ Vec3(0, -PHI, -1)
+};
+/* indices that map to 20hedron pts to create the polygons */
+enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
+static int icosa_idx[] = {
+ P11, P31, P21,
+ P11, P22, P33,
+ P13, P21, P32,
+ P13, P34, P22,
+ P12, P23, P31,
+ P12, P33, P24,
+ P14, P32, P23,
+ P14, P24, P34,
+
+ P11, P33, P31,
+ P12, P31, P33,
+ P13, P32, P34,
+ P14, P34, P32,
+
+ P21, P13, P11,
+ P22, P11, P13,
+ P23, P12, P14,
+ P24, P14, P12,
+
+ P31, P23, P21,
+ P32, P21, P23,
+ P33, P22, P24,
+ P34, P24, P22
+};
+
+static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
+{
+ if(!iter) {
+ verts->push_back(v1);
+ verts->push_back(v2);
+ verts->push_back(v3);
+ return;
+ }
+
+ /* we find mid points of the 3 vertices + normalize */
+
+ Vec3 v12 = normalize(v1 + v2);
+ Vec3 v23 = normalize(v2 + v3);
+ Vec3 v31 = normalize(v3 + v1);
+
+ /* create 4 triangles (recursive subdivision of the initial icosahedron */
+
+ geosphere(verts, v1, v12, v31, iter - 1);
+ geosphere(verts, v2, v23, v12, iter - 1);
+ geosphere(verts, v3, v31, v23, iter - 1);
+ geosphere(verts, v12, v23, v31, iter - 1);
+}
+
+void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
+{
+ /* the triangles of the icosahedron (fixed) */
+ int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
+
+ std::vector<Vec3> verts;
+ for(int i=0; i<num_tri; i++) {
+ Vec3 v[3];
+
+ /* we select the 3 vertices from the i-th triangle of the 20hedron */
+ for(int j=0; j<3; j++) {
+ int vidx = icosa_idx[i * 3 + j];
+ v[j] = normalize(icosa_pt[vidx]);
+ }
+
+ /* if hemi, we discard the triangles of the lower part of the 20hedron */
+ if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
+ continue;
+ }
+
+ geosphere(&verts, v[0], v[1], v[2], subdiv);
+ }
+
+ /* now the verts contains all the sphere vertices */
+
+ int num_verts = (int)verts.size();
+
+ mesh->vertices.resize(num_verts);
+ mesh->normals.resize(num_verts);
+ mesh->tex_coords.resize(num_verts);
+
+ for(int i=0; i<num_verts; i++) {
+ mesh->vertices[i] = verts[i] * rad;
+ mesh->normals[i] = verts[i];
+
+ float theta = atan2(verts[i].z, verts[i].x);
+ float phi = acos(verts[i].y);
+
+ float u = 0.5 * theta / M_PI + 0.5;
+ float v = phi / M_PI;
+ mesh->tex_coords[i] = Vec2(u, v);
+ }
+
+ /* TODO: optimize indices by detecting the common vertices */
+ mesh->indices.resize(num_verts);
+ for(int i=0; i<num_verts; i++) {
+ mesh->indices[i] = i;
+ }
+ mesh->update_vertex_data();
+}
\ No newline at end of file