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 }