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 }