1 module sbylib.graphics.util.model;
2 
3 import std;
4 import sbylib.math;
5 import sbylib.graphics.geometry;
6 import sbylib.wrapper.vulkan;
7 import sbylib.wrapper.assimp;
8 import sbylib.wrapper.assimp : AssimpScene = Scene,
9        AssimpNode = Node, 
10        AssimpMesh = Mesh, 
11        AssimpMaterial = Material,
12        AssimpPrimitiveType = PrimitiveType,
13        AssimpPropertyTypeInfo = PropertyTypeInfo;
14 
15 ModelNode loadModel(string path, PostProcessFlag flags = PostProcessFlag.None) {
16     Assimp.initialize();
17     auto scene = AssimpScene.fromFile(path, flags);
18     return new ModelNode(scene.rootNode, scene);
19 }
20 
21 class ModelNode {
22     ModelNode[] children;
23     ModelMesh[] meshes;
24     mat4 transformation;
25 
26     this(AssimpNode node, AssimpScene scene) {
27         this.children = node.children.map!(c => new ModelNode(c, scene)).array;
28         this.meshes = node.meshes.map!(i => new ModelMesh(scene.meshes[i], scene)).array;
29         this.transformation = node.transformation;
30     }
31 }
32 
33 private class ModelMesh {
34     ModelGeometry geom;
35     string name;
36     Variant[string] material;
37 
38     this(AssimpMesh mesh, AssimpScene scene) {
39         this.geom = createGeometry(mesh);
40         this.name = mesh.name;
41         if (mesh.materialIndex >= 0) {
42             this.material = createMaterial(scene.materials[mesh.materialIndex]);
43         }
44     }
45 }
46 
47 struct ModelVertex {
48     vec3 position;
49     vec3 normal;
50 }
51 
52 alias ModelGeometry = Geometry!(ModelVertex, uint);
53 
54 private ModelGeometry createGeometry(AssimpMesh mesh) {
55     with (ModelGeometry()) {
56         with (mesh) {
57             primitive = conv(primitiveTypes);
58             foreach (t; zip(vertices, normals)) {
59                 add(ModelVertex(t.expand));
60             }
61             foreach (face; faces) {
62                 foreach (i; face.indices) {
63                     select(i);
64                 }
65             }
66         }
67         return build();
68     }
69 }
70 
71 private PrimitiveTopology conv(BitFlags!AssimpPrimitiveType t) {
72     if (t & AssimpPrimitiveType.Point)    return PrimitiveTopology.PointList;
73     if (t & AssimpPrimitiveType.Line)     return PrimitiveTopology.LineList;
74     if (t & AssimpPrimitiveType.Triangle) return PrimitiveTopology.TriangleList;
75     if (t & AssimpPrimitiveType.Polygon) return PrimitiveTopology.TriangleStrip;
76     assert(false);
77 }
78 
79 private Variant[string] createMaterial(AssimpMaterial mat) {
80     Variant[string] result;
81     foreach (prop; mat.properties) {
82         final switch (prop.type) {
83             case AssimpPropertyTypeInfo.Float:
84                 result[prop.key] = prop.data!float;
85                 break;
86             case AssimpPropertyTypeInfo.String:
87                 result[prop.key] = prop.data!string;
88                 break;
89             case AssimpPropertyTypeInfo.Integer:
90                 result[prop.key] = prop.data!int;
91                 break;
92             case AssimpPropertyTypeInfo.Buffer:
93                 assert(false);
94         }
95     }
96     return result;
97 }