fb4fae2545a797c338f4c2bdd3e2d9060b512548
[demo] / src / meshgen.cc
1 #include <stdio.h>
2 #include "meshgen.h"
3 #include "mesh.h"
4
5 // ------ geosphere ------
6 #define PHI             1.618034
7
8 /* icosahedron points */
9 static Vec3 icosa_pt[] = {
10         Vec3(PHI, 1, 0),
11         Vec3(-PHI, 1, 0),
12         Vec3(PHI, -1, 0),
13         Vec3(-PHI, -1, 0),
14         Vec3(1, 0, PHI),
15         Vec3(1, 0, -PHI),
16         Vec3(-1, 0, PHI),
17         Vec3(-1, 0, -PHI),
18         Vec3(0, PHI, 1),
19         Vec3(0, -PHI, 1),
20         Vec3(0, PHI, -1),
21         Vec3(0, -PHI, -1)
22 };
23 /* indices that map to 20hedron pts to create the polygons */
24 enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
25 static int icosa_idx[] = {
26         P11, P31, P21,
27         P11, P22, P33,
28         P13, P21, P32,
29         P13, P34, P22,
30         P12, P23, P31,
31         P12, P33, P24,
32         P14, P32, P23,
33         P14, P24, P34,
34
35         P11, P33, P31,
36         P12, P31, P33,
37         P13, P32, P34,
38         P14, P34, P32,
39
40         P21, P13, P11,
41         P22, P11, P13,
42         P23, P12, P14,
43         P24, P14, P12,
44
45         P31, P23, P21,
46         P32, P21, P23,
47         P33, P22, P24,
48         P34, P24, P22
49 };
50
51 static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
52 {
53         if(!iter) {
54                 verts->push_back(v1);
55                 verts->push_back(v2);
56                 verts->push_back(v3);
57                 return;
58         }
59
60         /* we find mid points of the 3 vertices + normalize */
61
62         Vec3 v12 = normalize(v1 + v2);
63         Vec3 v23 = normalize(v2 + v3);
64         Vec3 v31 = normalize(v3 + v1);
65
66         /* create 4 triangles (recursive subdivision of the initial icosahedron */
67
68         geosphere(verts, v1, v12, v31, iter - 1);
69         geosphere(verts, v2, v23, v12, iter - 1);
70         geosphere(verts, v3, v31, v23, iter - 1);
71         geosphere(verts, v12, v23, v31, iter - 1);
72 }
73
74 void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
75 {
76         /* the triangles of the icosahedron (fixed) */
77         int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
78
79         std::vector<Vec3> verts;
80         for(int i=0; i<num_tri; i++) {
81                 Vec3 v[3];
82
83                 /* we select the 3 vertices from the i-th triangle of the 20hedron */
84                 for(int j=0; j<3; j++) {
85                         int vidx = icosa_idx[i * 3 + j];
86                         v[j] = normalize(icosa_pt[vidx]);
87                 }
88
89                 /* if hemi, we discard the triangles of the lower part of the 20hedron */
90                 if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
91                         continue;
92                 }
93
94                 geosphere(&verts, v[0], v[1], v[2], subdiv);
95         }
96
97         /* now the verts contains all the sphere vertices */
98
99         int num_verts = (int)verts.size();
100
101         mesh->vertices.resize(num_verts);
102         mesh->normals.resize(num_verts);
103         mesh->tex_coords.resize(num_verts);
104
105         for(int i=0; i<num_verts; i++) {
106                 mesh->vertices[i] = verts[i] * rad;
107                 mesh->normals[i] = verts[i];
108
109                 float theta = atan2(verts[i].z, verts[i].x);
110                 float phi = acos(verts[i].y);
111
112                 float u = 0.5 * theta / M_PI + 0.5;
113                 float v = phi / M_PI;
114                 mesh->tex_coords[i] = Vec2(u, v);
115         }
116
117         /* TODO: optimize indices by detecting the common vertices */
118         mesh->indices.resize(num_verts);
119         for(int i=0; i<num_verts; i++) {
120                 mesh->indices[i] = i;
121         }
122         mesh->update_vertex_data();
123 }