public static void AssimpPRMConvert(string initialFilePath, string finalFilePath)
        {
            Assimp.AssimpContext context = new Assimp.AssimpContext();
            context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false));
            Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs);

            PRMModel prm = new PRMModel();

            int totalVerts = 0;

            //Iterate through and combine meshes. PRMs can only have a single mesh
            IterateAiNodesPRM(prm, ref totalVerts, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform)));
            AquaUtil.WritePRMToFile(prm, finalFilePath, 4);
        }
        private static void IterateAiNodesPRM(PRMModel prm, ref int totalVerts, Assimp.Scene aiScene, Assimp.Node node, Matrix4x4 parentTfm)
        {
            Matrix4x4 nodeMat = Matrix4x4.Transpose(GetMat4FromAssimpMat4(node.Transform));

            nodeMat = Matrix4x4.Multiply(nodeMat, parentTfm);

            foreach (int meshId in node.MeshIndices)
            {
                var mesh = aiScene.Meshes[meshId];
                AddAiMeshToPRM(prm, ref totalVerts, mesh, nodeMat);
            }

            foreach (var childNode in node.Children)
            {
                IterateAiNodesPRM(prm, ref totalVerts, aiScene, childNode, nodeMat);
            }
        }
        public static Assimp.Scene AssimpPRMExport(string filePath, PRMModel prm)
        {
            Assimp.Scene aiScene = new Assimp.Scene();

            //Create an array to hold references to these since Assimp lacks a way to grab these by order or id
            //We don't need the nodo count in this since they can't be parents
            Assimp.Node[] boneArray = new Assimp.Node[2];

            //Set up root node
            var aiRootNode = new Assimp.Node("RootNode", null);

            aiRootNode.Transform = Assimp.Matrix4x4.Identity;

            boneArray[0]     = aiRootNode;
            aiScene.RootNode = aiRootNode;

            //Set up single child node
            var aiNode = new Assimp.Node(Path.GetFileNameWithoutExtension(filePath) + "_node", aiRootNode);

            //Use inverse bind matrix as base

            //Get local transform
            aiNode.Transform = aiRootNode.Transform;

            aiRootNode.Children.Add(aiNode);
            boneArray[1] = aiNode;

            //Mesh
            string aiMeshName = Path.GetFileNameWithoutExtension(filePath);

            var aiMesh = new Assimp.Mesh(aiMeshName, Assimp.PrimitiveType.Triangle);

            //Vertex face data - PSO2 Actually doesn't do this, it just has per vertex data so we can just map a vertice's data to each face using it
            //It may actually be possible to add this to the previous loop, but my reference didn't so I'm doing it in a separate loop for safety
            //Reference: https://github.com/TGEnigma/Amicitia/blob/master/Source/AmicitiaLibrary/Graphics/RenderWare/RWClumpNode.cs
            for (int vertId = 0; vertId < prm.vertices.Count; vertId++)
            {
                var prmVert = prm.vertices[vertId];

                var pos = prmVert.pos * 100;
                aiMesh.Vertices.Add(new Assimp.Vector3D(pos.X, pos.Y, pos.Z));

                var nrm = prmVert.normal;
                aiMesh.Normals.Add(new Assimp.Vector3D(nrm.X, nrm.Y, nrm.Z));

                //Vert colors are bgra
                var rawClr = prmVert.color;
                var clr    = new Assimp.Color4D(clrToFloat(rawClr[2]), clrToFloat(rawClr[1]), clrToFloat(rawClr[0]), clrToFloat(rawClr[3]));
                aiMesh.VertexColorChannels[0].Add(clr);

                var uv1   = prmVert.uv1;
                var aiUV1 = new Assimp.Vector3D(uv1.X, uv1.Y, 0f);
                aiMesh.TextureCoordinateChannels[0].Add(aiUV1);


                var uv2   = prmVert.uv2;
                var aiUV2 = new Assimp.Vector3D(uv2.X, uv2.Y, 0f);
                aiMesh.TextureCoordinateChannels[1].Add(aiUV2);
            }

            //Handle rigid meshes
            {
                var aiBone  = new Assimp.Bone();
                var aqnBone = boneArray[0];

                // Name
                aiBone.Name = aiNode.Name;

                // VertexWeights
                for (int i = 0; i < aiMesh.Vertices.Count; i++)
                {
                    var aiVertexWeight = new Assimp.VertexWeight(i, 1f);
                    aiBone.VertexWeights.Add(aiVertexWeight);
                }

                aiBone.OffsetMatrix = Assimp.Matrix4x4.Identity;

                aiMesh.Bones.Add(aiBone);
            }

            //Faces
            foreach (var face in prm.faces)
            {
                aiMesh.Faces.Add(new Assimp.Face(new int[] { (int)face.X, (int)face.Y, (int)face.Z }));
            }

            //Material
            Assimp.Material mate = new Assimp.Material();

            mate.ColorDiffuse = new Assimp.Color4D(1, 1, 1, 1);
            mate.Name         = aiMeshName + "_material";

            mate.ShadingMode = Assimp.ShadingMode.Phong;

            var meshNodeName = Path.GetFileNameWithoutExtension(filePath);

            // Add mesh to meshes
            aiScene.Meshes.Add(aiMesh);

            // Add material to materials
            aiScene.Materials.Add(mate);

            // MaterialIndex
            aiMesh.MaterialIndex = aiScene.Materials.Count - 1;

            // Set up mesh node and add this mesh's index to it (This tells assimp to export it as a mesh for various formats)
            var meshNode = new Assimp.Node(meshNodeName, aiScene.RootNode);

            meshNode.Transform = Assimp.Matrix4x4.Identity;

            aiScene.RootNode.Children.Add(meshNode);

            meshNode.MeshIndices.Add(aiScene.Meshes.Count - 1);


            return(aiScene);
        }
        private static void AddAiMeshToPRM(PRMModel prm, ref int totalVerts, Assimp.Mesh aiMesh, Matrix4x4 nodeMat)
        {
            //Convert vertices
            for (int vertId = 0; vertId < aiMesh.VertexCount; vertId++)
            {
                PRMModel.PRMVert vert = new PRMModel.PRMVert();
                var aiPos             = aiMesh.Vertices[vertId];
                var newPos            = (new Vector3(aiPos.X, aiPos.Y, aiPos.Z));
                vert.pos = Vector3.Transform(newPos, nodeMat) / 100;

                if (aiMesh.HasVertexColors(0))
                {
                    var aiColor = aiMesh.VertexColorChannels[0][vertId];
                    vert.color = new byte[] { (byte)(aiColor.B * 255), (byte)(aiColor.G * 255), (byte)(aiColor.R * 255), (byte)(aiColor.A * 255) };
                }
                else
                {
                    vert.color = new byte[4];
                }

                if (aiMesh.HasNormals)
                {
                    var aiNorm = aiMesh.Normals[vertId];
                    var normal = new Vector3(aiNorm.X, aiNorm.Y, aiNorm.Z);
                    vert.normal = Vector3.TransformNormal(normal, nodeMat);
                }
                else
                {
                    vert.normal = new Vector3();
                }

                if (aiMesh.HasTextureCoords(0))
                {
                    var aiUV1 = aiMesh.TextureCoordinateChannels[0][vertId];
                    vert.uv1 = new Vector2(aiUV1.X, aiUV1.Y);
                }
                else
                {
                    vert.uv1 = new Vector2();
                }

                if (aiMesh.HasTextureCoords(1))
                {
                    var aiUV2 = aiMesh.TextureCoordinateChannels[1][vertId];
                    vert.uv2 = new Vector2(aiUV2.X, aiUV2.Y);
                }
                else
                {
                    vert.uv2 = new Vector2();
                }

                prm.vertices.Add(vert);
            }

            //Convert Faces
            foreach (var aiFace in aiMesh.Faces)
            {
                prm.faces.Add(new Vector3(aiFace.Indices[0] + totalVerts, aiFace.Indices[1] + totalVerts, aiFace.Indices[2] + totalVerts));
            }

            //Keep count up to date for next potential loop
            totalVerts = prm.vertices.Count;
        }