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 }