1 module gfx.genmesh.cube;
2 
3 import gfx.genmesh.poly;
4 
5 import std.typecons : Flag, Yes;
6 
7 
8 
9 auto genCube(Flag!"normals" normals = Yes.normals)() {
10     return CubeGenerator!normals.init;
11 }
12 
13 /// cube face generator
14 /// pass Yes.normals as parameter to get vertices normals
15 struct CubeGenerator(Flag!"normals" normals) {
16 
17     alias GV = GenVertex!normals;
18 
19     private size_t faceFrontIdx =0;
20     private size_t faceBackIdx  =6;
21 
22 
23     Quad!GV face(in size_t fi) const {
24         static if (normals == Yes.normals) {
25             float[3] normal () {
26                 switch (fi) {
27                     case 0: return [ 0,  0,  1 ];
28                     case 1: return [ 0,  0, -1 ];
29                     case 2: return [ 0,  1,  0 ];
30                     case 3: return [ 0, -1,  0 ];
31                     case 4: return [ 1,  0,  0 ];
32                     case 5: return [-1,  0,  0 ];
33                     default: assert(false);
34                 }
35             }
36             immutable n = normal();
37         }
38 
39         Quad!ubyte maskFace() {
40             switch (fi) {
41                 case 0: return quad!ubyte(0b001, 0b101, 0b111, 0b011);    // Z+
42                 case 1: return quad!ubyte(0b100, 0b000, 0b010, 0b110);    // Z-
43                 case 2: return quad!ubyte(0b011, 0b111, 0b110, 0b010);    // Y+
44                 case 3: return quad!ubyte(0b101, 0b001, 0b000, 0b100);    // Y-
45                 case 4: return quad!ubyte(0b101, 0b100, 0b110, 0b111);    // X+
46                 case 5: return quad!ubyte(0b000, 0b001, 0b011, 0b010);    // X-
47                 default: assert(false);
48             }
49         }
50 
51         import gfx.genmesh.algorithm : vertexMap;
52 
53         return maskFace().vertexMap!((ubyte m) {
54             immutable x = (m & 0b100) ? 1f : -1f;
55             immutable y = (m & 0b010) ? 1f : -1f;
56             immutable z = (m & 0b001) ? 1f : -1f;
57             static if (normals == Yes.normals)
58                 return GV([x, y, z], n);
59             else
60                 return GV([x, y, z]);
61         });
62     }
63 
64     // input
65     @property Quad!GV front() const { return face(faceFrontIdx); }
66 
67     void popFront() { faceFrontIdx += 1; }
68 
69     @property bool empty() const { return faceFrontIdx >= faceBackIdx; }
70 
71     // forward
72     @property auto save() const {
73         return typeof(this)(faceFrontIdx, faceBackIdx);
74     }
75 
76     // bidir
77     @property Quad!GV back() const { return face(faceBackIdx-1); }
78 
79     void popBack() { faceBackIdx -= 1; }
80 
81     // random access
82     @property size_t length() const { return faceBackIdx - faceFrontIdx; }
83 
84     Quad!GV opIndex(in size_t fIdx) const {
85         return face(fIdx);
86     }
87 }
88 
89 
90 ///
91 unittest {
92     import gfx.genmesh.algorithm;
93     import std.algorithm : map, each, equal;
94     import std.stdio;
95 
96     struct Vertex {
97         float[3] pos;
98         float[3] normal;
99         float[2] texCoord;
100     }
101     auto cube = genCube()                               // faces of internal vertex type
102             .vertexMap!((v) {
103                 return typeof(v)([2*v.p[0], 2*v.p[1], 2*v.p[2]], v.n);
104             })                                          // same face type with a transform (scaled by 2)
105             .map!(f => quad(
106                 Vertex(f[0].p, f[0].n, [0f, 0f]),
107                 Vertex(f[1].p, f[1].n, [0f, 1f]),
108                 Vertex(f[2].p, f[2].n, [1f, 1f]),
109                 Vertex(f[3].p, f[3].n, [1f, 0f]),
110             ))                                          // faces with application vertex type (tex coord added)
111             .triangulate()                              // triangular faces (with app vertex type)
112             .vertices()                                 // application vertices
113             .indexCollectMesh();                        // mesh type with array members "indices" and "vertices"
114 
115     // only the last step actually pull and transform the data all along the chain
116 
117     foreach (f; 0 .. 6) {
118         immutable f6 = f*6;
119         immutable f4 = f*4;
120         assert(cube.indices[f6 .. f6+6].equal([f4, f4+1, f4+2, f4, f4+2, f4+3]));
121     }
122 }