1 module sbylib.graphics.geometry.geometry3d.icosahedron;
2 
3 import std : map, array, sqrt;
4 import sbylib.math;
5 import sbylib.wrapper.vulkan;
6 import sbylib.graphics.geometry.geometry;
7 
8 auto buildGeometry(uint level = 0) {
9     struct Vertex {
10         vec3 position;
11         vec3 normal;
12         vec2 uv;
13     }
14 
15     with (Geometry!(Vertex, uint)()) {
16         primitive = PrimitiveTopology.TriangleList;
17         auto vertexIndex = createVertexIndex(level);
18 
19         foreach (v; vertexIndex.vertex) {
20             Vertex vertex = {
21                 position: v,
22                 normal: v
23             };
24             add(vertex);
25         }
26         foreach (index; vertexIndex.index) {
27             select(index);
28         }
29 
30         return build();
31     }
32 }
33 
34 private auto createVertexIndex(uint level) {
35     struct Result {
36         vec3[] vertex;
37         uint[] index;
38     }
39 
40     if (level == 0) return Result(OriginalVertex, OriginalIndex);
41 
42     Result result = createVertexIndex(level-1);
43 
44     with (result) {
45         uint idx = cast(uint)vertex.length;
46 
47         uint[uint] cache;
48         uint getMiddleIndex(uint a, uint b) {
49             const key = a < b ? (a * 114_514 + b) : (b * 114_514 + a);
50             if (auto r = key in cache) return *r;
51             auto newVertex = normalize(vertex[a] + vertex[b]);
52             vertex ~= newVertex;
53             cache[key] = idx;
54             return idx++;
55         }
56 
57         const faceNum = index.length/3;
58 
59         foreach (i; 0..faceNum) {
60             const v0 = getMiddleIndex(index[i*3+0],index[i*3+1]);
61             const v1 = getMiddleIndex(index[i*3+1],index[i*3+2]);
62             const v2 = getMiddleIndex(index[i*3+2],index[i*3+0]);
63 
64             index ~= [index[i*3+0], v0, v2];
65             index ~= [v0, index[i*3+1], v1];
66             index ~= [v2,v1,index[i*3+2]];
67             index ~= [v0, v1, v2];
68         }
69     }
70 
71     return result;
72 }
73 
74 
75 private enum GoldenRatio = (1 + sqrt(5.0f)) / 2;
76 
77 private enum OriginalVertex = [
78     vec3(-1, +GoldenRatio, 0),
79     vec3(+1, +GoldenRatio, 0),
80     vec3(-1, -GoldenRatio, 0),
81     vec3(+1, -GoldenRatio, 0),
82 
83     vec3(0, -1, +GoldenRatio),
84     vec3(0, +1, +GoldenRatio),
85     vec3(0, -1, -GoldenRatio),
86     vec3(0, +1, -GoldenRatio),
87 
88     vec3(+GoldenRatio, 0, -1),
89     vec3(+GoldenRatio, 0, +1),
90     vec3(-GoldenRatio, 0, -1),
91     vec3(-GoldenRatio, 0, +1)
92 ].map!(v => normalize(v)).array;
93 
94 private enum OriginalIndex = [
95     0,  11,  5,
96     0,   5,  1,
97     0,   1,  7,
98     0,   7, 10,
99     0,  10, 11,
100 
101     1,   5,  9,
102     5,  11,  4,
103     11,  10,  2,
104     10,   7,  6,
105     7,   1,  8,
106 
107     3,   9,  4,
108     3,   4,  2,
109     3,   2,  6,
110     3,   6,  8,
111     3,   8,  9,
112 
113     4,   9,  5,
114     2,   4, 11,
115     6,   2, 10,
116     8,   6,  7,
117     9,   8,  1
118 ];