--- /dev/null
+#include <assimp/Importer.hpp>
+#include <assimp/postprocess.h>
+#include "blendshapes.hpp"
+#include "util.hpp"
+
+void createBlendshapes(std::vector<std::string> blendshapes, std::string neutral, Program p, Blendshapes *res) {
+
+ Assimp::Importer importer;
+ unsigned int ppFlags = aiProcess_Triangulate | aiProcess_CalcTangentSpace | aiProcess_GenNormals;
+ importer.ReadFile(neutral, ppFlags);
+ const aiScene *scene = importer.GetOrphanedScene();
+
+ res->model = new Model(scene, p);
+
+ assert(scene->mNumMeshes == 1);
+
+ const aiMesh *neutralMesh = scene->mMeshes[0];
+ res->neutral = std::vector<glm::vec3>(neutralMesh->mNumVertices);
+ res->deltas = std::vector<std::vector<glm::vec3>>(blendshapes.size());
+ for (int i = 0; i < neutralMesh->mNumVertices; i++)
+ res->neutral[i] = aiVector3DToVec3(neutralMesh->mVertices[i]);
+
+ for (int i = 0; i < blendshapes.size(); i++) {
+ auto fp = blendshapes[i];
+ const aiScene *blendshape = importer.ReadFile(fp, ppFlags);
+ if (blendshape->mNumMeshes != 1) {
+ std::cerr << "Too many or too little meshes for the blendshape " << fp << std::endl;
+ abort();
+ }
+ aiMesh *mesh = blendshape->mMeshes[0];
+ std::vector<glm::vec3> meshDeltas(mesh->mNumVertices);
+ assert(mesh->mNumVertices == neutralMesh->mNumVertices);
+ for (int j = 0; j < mesh->mNumVertices; j++) {
+ glm::vec3 d = aiVector3DToVec3(mesh->mVertices[j]) - aiVector3DToVec3(neutralMesh->mVertices[j]);
+ meshDeltas[j] = d;
+ }
+ res->deltas[i] = meshDeltas;
+ }
+
+}
+
+void interpolateBlendshapes(Blendshapes *b, std::vector<float> weights) {
+ assert(weights.size() == b->deltas.size());
+ const Model::Mesh mesh = b->model->meshes[0];
+
+ for (int i = 0; i < mesh.ai.mNumVertices; i++) {
+ glm::vec3 pos = b->neutral[i];
+ for (int j = 0; j < b->deltas.size(); j++) {
+ pos += b->deltas[j][i] * weights[j];
+ }
+ mesh.ai.mVertices[i] = vec3ToaiVector3D(pos);
+ }
+
+ mesh.updatePosBuffer();
+}