summaryrefslogtreecommitdiff
path: root/thirdparty/assimp/code/MMD
diff options
context:
space:
mode:
authorRevoluPowered <gordon@gordonite.tech>2019-07-29 23:54:00 +0100
committerRevoluPowered <gordon@gordonite.tech>2019-07-30 18:59:29 +0100
commit243f400ee201aa59f23ec073983b8557d641d01a (patch)
treed6de9b21b369c22afc79f64b67cf3805ae97854f /thirdparty/assimp/code/MMD
parent73d2a997616be6b91bc1fecbf4745abe88f85a92 (diff)
Updated assimp to commit 1d565b0 with iFire
Signed-off-by: RevoluPowered <gordon@gordonite.tech> Signed-off-by: K. S. Ernest (iFIre) Lee <ernest.lee@chibifire.com>
Diffstat (limited to 'thirdparty/assimp/code/MMD')
-rw-r--r--thirdparty/assimp/code/MMD/MMDCpp14.h83
-rw-r--r--thirdparty/assimp/code/MMD/MMDImporter.cpp372
-rw-r--r--thirdparty/assimp/code/MMD/MMDImporter.h96
-rw-r--r--thirdparty/assimp/code/MMD/MMDPmdParser.h597
-rw-r--r--thirdparty/assimp/code/MMD/MMDPmxParser.cpp608
-rw-r--r--thirdparty/assimp/code/MMD/MMDPmxParser.h782
-rw-r--r--thirdparty/assimp/code/MMD/MMDVmdParser.h376
7 files changed, 2914 insertions, 0 deletions
diff --git a/thirdparty/assimp/code/MMD/MMDCpp14.h b/thirdparty/assimp/code/MMD/MMDCpp14.h
new file mode 100644
index 0000000000..638b0bfd2f
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDCpp14.h
@@ -0,0 +1,83 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#ifndef MMD_CPP14_H
+#define MMD_CPP14_H
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace mmd {
+ template<class T> struct _Unique_if {
+ typedef std::unique_ptr<T> _Single_object;
+ };
+
+ template<class T> struct _Unique_if<T[]> {
+ typedef std::unique_ptr<T[]> _Unknown_bound;
+ };
+
+ template<class T, size_t N> struct _Unique_if<T[N]> {
+ typedef void _Known_bound;
+ };
+
+ template<class T, class... Args>
+ typename _Unique_if<T>::_Single_object
+ make_unique(Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+ }
+
+ template<class T>
+ typename _Unique_if<T>::_Unknown_bound
+ make_unique(size_t n) {
+ typedef typename std::remove_extent<T>::type U;
+ return std::unique_ptr<T>(new U[n]());
+ }
+
+ template<class T, class... Args>
+ typename _Unique_if<T>::_Known_bound
+ make_unique(Args&&...) = delete;
+}
+
+#endif
diff --git a/thirdparty/assimp/code/MMD/MMDImporter.cpp b/thirdparty/assimp/code/MMD/MMDImporter.cpp
new file mode 100644
index 0000000000..e7744e4cd0
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDImporter.cpp
@@ -0,0 +1,372 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
+
+#include "MMD/MMDImporter.h"
+#include "MMD/MMDPmdParser.h"
+#include "MMD/MMDPmxParser.h"
+#include "MMD/MMDVmdParser.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/Importer.hpp>
+#include <assimp/ai_assert.h>
+#include <assimp/scene.h>
+
+#include <fstream>
+#include <iomanip>
+#include <memory>
+
+static const aiImporterDesc desc = {"MMD Importer",
+ "",
+ "",
+ "surfaces supported?",
+ aiImporterFlags_SupportTextFlavour,
+ 0,
+ 0,
+ 0,
+ 0,
+ "pmx"};
+
+namespace Assimp {
+
+using namespace std;
+
+// ------------------------------------------------------------------------------------------------
+// Default constructor
+MMDImporter::MMDImporter()
+: m_Buffer()
+, m_strAbsPath("") {
+ DefaultIOSystem io;
+ m_strAbsPath = io.getOsSeparator();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor.
+MMDImporter::~MMDImporter() {
+ // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns true, if file is an pmx file.
+bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler,
+ bool checkSig) const {
+ if (!checkSig) // Check File Extension
+ {
+ return SimpleExtensionCheck(pFile, "pmx");
+ } else // Check file Header
+ {
+ static const char *pTokens[] = {"PMX "};
+ return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 1);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiImporterDesc *MMDImporter::GetInfo() const { return &desc; }
+
+// ------------------------------------------------------------------------------------------------
+// MMD import implementation
+void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
+ IOSystem * /*pIOHandler*/) {
+ // Read file by istream
+ std::filebuf fb;
+ if (!fb.open(file, std::ios::in | std::ios::binary)) {
+ throw DeadlyImportError("Failed to open file " + file + ".");
+ }
+
+ std::istream fileStream(&fb);
+
+ // Get the file-size and validate it, throwing an exception when fails
+ fileStream.seekg(0, fileStream.end);
+ size_t fileSize = static_cast<size_t>(fileStream.tellg());
+ fileStream.seekg(0, fileStream.beg);
+
+ if (fileSize < sizeof(pmx::PmxModel)) {
+ throw DeadlyImportError(file + " is too small.");
+ }
+
+ pmx::PmxModel model;
+ model.Read(&fileStream);
+
+ CreateDataFromImport(&model, pScene);
+}
+
+// ------------------------------------------------------------------------------------------------
+void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel,
+ aiScene *pScene) {
+ if (pModel == NULL) {
+ return;
+ }
+
+ aiNode *pNode = new aiNode;
+ if (!pModel->model_name.empty()) {
+ pNode->mName.Set(pModel->model_name);
+ }
+
+ pScene->mRootNode = pNode;
+
+ pNode = new aiNode;
+ pScene->mRootNode->addChildren(1, &pNode);
+ pNode->mName.Set(string(pModel->model_name) + string("_mesh"));
+
+ // split mesh by materials
+ pNode->mNumMeshes = pModel->material_count;
+ pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
+ for (unsigned int index = 0; index < pNode->mNumMeshes; index++) {
+ pNode->mMeshes[index] = index;
+ }
+
+ pScene->mNumMeshes = pModel->material_count;
+ pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
+ for (unsigned int i = 0, indexStart = 0; i < pScene->mNumMeshes; i++) {
+ const int indexCount = pModel->materials[i].index_count;
+
+ pScene->mMeshes[i] = CreateMesh(pModel, indexStart, indexCount);
+ pScene->mMeshes[i]->mName = pModel->materials[i].material_name;
+ pScene->mMeshes[i]->mMaterialIndex = i;
+ indexStart += indexCount;
+ }
+
+ // create node hierarchy for bone position
+ std::unique_ptr<aiNode *[]> ppNode(new aiNode *[pModel->bone_count]);
+ for (auto i = 0; i < pModel->bone_count; i++) {
+ ppNode[i] = new aiNode(pModel->bones[i].bone_name);
+ }
+
+ for (auto i = 0; i < pModel->bone_count; i++) {
+ const pmx::PmxBone &bone = pModel->bones[i];
+
+ if (bone.parent_index < 0) {
+ pScene->mRootNode->addChildren(1, ppNode.get() + i);
+ } else {
+ ppNode[bone.parent_index]->addChildren(1, ppNode.get() + i);
+
+ aiVector3D v3 = aiVector3D(
+ bone.position[0] - pModel->bones[bone.parent_index].position[0],
+ bone.position[1] - pModel->bones[bone.parent_index].position[1],
+ bone.position[2] - pModel->bones[bone.parent_index].position[2]);
+ aiMatrix4x4::Translation(v3, ppNode[i]->mTransformation);
+ }
+ }
+
+ // create materials
+ pScene->mNumMaterials = pModel->material_count;
+ pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
+ for (unsigned int i = 0; i < pScene->mNumMaterials; i++) {
+ pScene->mMaterials[i] = CreateMaterial(&pModel->materials[i], pModel);
+ }
+
+ // Convert everything to OpenGL space
+ MakeLeftHandedProcess convertProcess;
+ convertProcess.Execute(pScene);
+
+ FlipUVsProcess uvFlipper;
+ uvFlipper.Execute(pScene);
+
+ FlipWindingOrderProcess windingFlipper;
+ windingFlipper.Execute(pScene);
+}
+
+// ------------------------------------------------------------------------------------------------
+aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
+ const int indexStart, const int indexCount) {
+ aiMesh *pMesh = new aiMesh;
+
+ pMesh->mNumVertices = indexCount;
+
+ pMesh->mNumFaces = indexCount / 3;
+ pMesh->mFaces = new aiFace[pMesh->mNumFaces];
+
+ const int numIndices = 3; // triangular face
+ for (unsigned int index = 0; index < pMesh->mNumFaces; index++) {
+ pMesh->mFaces[index].mNumIndices = numIndices;
+ unsigned int *indices = new unsigned int[numIndices];
+ indices[0] = numIndices * index;
+ indices[1] = numIndices * index + 1;
+ indices[2] = numIndices * index + 2;
+ pMesh->mFaces[index].mIndices = indices;
+ }
+
+ pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+ pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
+ pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
+ pMesh->mNumUVComponents[0] = 2;
+
+ // additional UVs
+ for (int i = 1; i <= pModel->setting.uv; i++) {
+ pMesh->mTextureCoords[i] = new aiVector3D[pMesh->mNumVertices];
+ pMesh->mNumUVComponents[i] = 4;
+ }
+
+ map<int, vector<aiVertexWeight>> bone_vertex_map;
+
+ // fill in contents and create bones
+ for (int index = 0; index < indexCount; index++) {
+ const pmx::PmxVertex *v =
+ &pModel->vertices[pModel->indices[indexStart + index]];
+ const float *position = v->position;
+ pMesh->mVertices[index].Set(position[0], position[1], position[2]);
+ const float *normal = v->normal;
+
+ pMesh->mNormals[index].Set(normal[0], normal[1], normal[2]);
+ pMesh->mTextureCoords[0][index].x = v->uv[0];
+ pMesh->mTextureCoords[0][index].y = v->uv[1];
+
+ for (int i = 1; i <= pModel->setting.uv; i++) {
+ // TODO: wrong here? use quaternion transform?
+ pMesh->mTextureCoords[i][index].x = v->uva[i][0];
+ pMesh->mTextureCoords[i][index].y = v->uva[i][1];
+ }
+
+ // handle bone map
+ const auto vsBDEF1_ptr =
+ dynamic_cast<pmx::PmxVertexSkinningBDEF1 *>(v->skinning.get());
+ const auto vsBDEF2_ptr =
+ dynamic_cast<pmx::PmxVertexSkinningBDEF2 *>(v->skinning.get());
+ const auto vsBDEF4_ptr =
+ dynamic_cast<pmx::PmxVertexSkinningBDEF4 *>(v->skinning.get());
+ const auto vsSDEF_ptr =
+ dynamic_cast<pmx::PmxVertexSkinningSDEF *>(v->skinning.get());
+ switch (v->skinning_type) {
+ case pmx::PmxVertexSkinningType::BDEF1:
+ bone_vertex_map[vsBDEF1_ptr->bone_index].push_back(
+ aiVertexWeight(index, 1.0));
+ break;
+ case pmx::PmxVertexSkinningType::BDEF2:
+ bone_vertex_map[vsBDEF2_ptr->bone_index1].push_back(
+ aiVertexWeight(index, vsBDEF2_ptr->bone_weight));
+ bone_vertex_map[vsBDEF2_ptr->bone_index2].push_back(
+ aiVertexWeight(index, 1.0f - vsBDEF2_ptr->bone_weight));
+ break;
+ case pmx::PmxVertexSkinningType::BDEF4:
+ bone_vertex_map[vsBDEF4_ptr->bone_index1].push_back(
+ aiVertexWeight(index, vsBDEF4_ptr->bone_weight1));
+ bone_vertex_map[vsBDEF4_ptr->bone_index2].push_back(
+ aiVertexWeight(index, vsBDEF4_ptr->bone_weight2));
+ bone_vertex_map[vsBDEF4_ptr->bone_index3].push_back(
+ aiVertexWeight(index, vsBDEF4_ptr->bone_weight3));
+ bone_vertex_map[vsBDEF4_ptr->bone_index4].push_back(
+ aiVertexWeight(index, vsBDEF4_ptr->bone_weight4));
+ break;
+ case pmx::PmxVertexSkinningType::SDEF: // TODO: how to use sdef_c, sdef_r0,
+ // sdef_r1?
+ bone_vertex_map[vsSDEF_ptr->bone_index1].push_back(
+ aiVertexWeight(index, vsSDEF_ptr->bone_weight));
+ bone_vertex_map[vsSDEF_ptr->bone_index2].push_back(
+ aiVertexWeight(index, 1.0f - vsSDEF_ptr->bone_weight));
+ break;
+ case pmx::PmxVertexSkinningType::QDEF:
+ const auto vsQDEF_ptr =
+ dynamic_cast<pmx::PmxVertexSkinningQDEF *>(v->skinning.get());
+ bone_vertex_map[vsQDEF_ptr->bone_index1].push_back(
+ aiVertexWeight(index, vsQDEF_ptr->bone_weight1));
+ bone_vertex_map[vsQDEF_ptr->bone_index2].push_back(
+ aiVertexWeight(index, vsQDEF_ptr->bone_weight2));
+ bone_vertex_map[vsQDEF_ptr->bone_index3].push_back(
+ aiVertexWeight(index, vsQDEF_ptr->bone_weight3));
+ bone_vertex_map[vsQDEF_ptr->bone_index4].push_back(
+ aiVertexWeight(index, vsQDEF_ptr->bone_weight4));
+ break;
+ }
+ }
+
+ // make all bones for each mesh
+ // assign bone weights to skinned bones (otherwise just initialize)
+ auto bone_ptr_ptr = new aiBone *[pModel->bone_count];
+ pMesh->mNumBones = pModel->bone_count;
+ pMesh->mBones = bone_ptr_ptr;
+ for (auto ii = 0; ii < pModel->bone_count; ++ii) {
+ auto pBone = new aiBone;
+ const auto &pmxBone = pModel->bones[ii];
+ pBone->mName = pmxBone.bone_name;
+ aiVector3D pos(pmxBone.position[0], pmxBone.position[1], pmxBone.position[2]);
+ aiMatrix4x4::Translation(-pos, pBone->mOffsetMatrix);
+ auto it = bone_vertex_map.find(ii);
+ if (it != bone_vertex_map.end()) {
+ pBone->mNumWeights = static_cast<unsigned int>(it->second.size());
+ pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
+ for (unsigned int j = 0; j < pBone->mNumWeights; j++) {
+ pBone->mWeights[j] = it->second[j];
+ }
+ }
+ bone_ptr_ptr[ii] = pBone;
+ }
+
+ return pMesh;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiMaterial *MMDImporter::CreateMaterial(const pmx::PmxMaterial *pMat,
+ const pmx::PmxModel *pModel) {
+ aiMaterial *mat = new aiMaterial();
+ aiString name(pMat->material_english_name);
+ mat->AddProperty(&name, AI_MATKEY_NAME);
+
+ aiColor3D diffuse(pMat->diffuse[0], pMat->diffuse[1], pMat->diffuse[2]);
+ mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
+ aiColor3D specular(pMat->specular[0], pMat->specular[1], pMat->specular[2]);
+ mat->AddProperty(&specular, 1, AI_MATKEY_COLOR_SPECULAR);
+ aiColor3D ambient(pMat->ambient[0], pMat->ambient[1], pMat->ambient[2]);
+ mat->AddProperty(&ambient, 1, AI_MATKEY_COLOR_AMBIENT);
+
+ float opacity = pMat->diffuse[3];
+ mat->AddProperty(&opacity, 1, AI_MATKEY_OPACITY);
+ float shininess = pMat->specularlity;
+ mat->AddProperty(&shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
+
+ if(pMat->diffuse_texture_index >= 0) {
+ aiString texture_path(pModel->textures[pMat->diffuse_texture_index]);
+ mat->AddProperty(&texture_path, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
+ }
+
+ int mapping_uvwsrc = 0;
+ mat->AddProperty(&mapping_uvwsrc, 1,
+ AI_MATKEY_UVWSRC(aiTextureType_DIFFUSE, 0));
+
+ return mat;
+}
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_MMD_IMPORTER
diff --git a/thirdparty/assimp/code/MMD/MMDImporter.h b/thirdparty/assimp/code/MMD/MMDImporter.h
new file mode 100644
index 0000000000..4ee94eeb00
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDImporter.h
@@ -0,0 +1,96 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef MMD_FILE_IMPORTER_H_INC
+#define MMD_FILE_IMPORTER_H_INC
+
+#include <assimp/BaseImporter.h>
+#include "MMDPmxParser.h"
+#include <assimp/material.h>
+#include <vector>
+
+struct aiMesh;
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+/// \class MMDImporter
+/// \brief Imports MMD a pmx/pmd/vmd file
+// ------------------------------------------------------------------------------------------------
+class MMDImporter : public BaseImporter {
+public:
+ /// \brief Default constructor
+ MMDImporter();
+
+ /// \brief Destructor
+ ~MMDImporter();
+
+public:
+ /// \brief Returns whether the class can handle the format of the given file.
+ /// \remark See BaseImporter::CanRead() for details.
+ bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+
+private:
+ //! \brief Appends the supported extension.
+ const aiImporterDesc* GetInfo () const;
+
+ //! \brief File import implementation.
+ void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+
+ //! \brief Create the data from imported content.
+ void CreateDataFromImport(const pmx::PmxModel* pModel, aiScene* pScene);
+
+ //! \brief Create the mesh
+ aiMesh* CreateMesh(const pmx::PmxModel* pModel, const int indexStart, const int indexCount);
+
+ //! \brief Create the material
+ aiMaterial* CreateMaterial(const pmx::PmxMaterial* pMat, const pmx::PmxModel* pModel);
+
+private:
+ //! Data buffer
+ std::vector<char> m_Buffer;
+ //! Absolute pathname of model in file system
+ std::string m_strAbsPath;
+};
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif \ No newline at end of file
diff --git a/thirdparty/assimp/code/MMD/MMDPmdParser.h b/thirdparty/assimp/code/MMD/MMDPmdParser.h
new file mode 100644
index 0000000000..d2f2224aa1
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDPmdParser.h
@@ -0,0 +1,597 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#include <vector>
+#include <string>
+#include <memory>
+#include <iostream>
+#include <fstream>
+#include "MMDCpp14.h"
+
+namespace pmd
+{
+ class PmdHeader
+ {
+ public:
+ std::string name;
+ std::string name_english;
+ std::string comment;
+ std::string comment_english;
+
+ bool Read(std::ifstream* stream)
+ {
+ char buffer[256];
+ stream->read(buffer, 20);
+ name = std::string(buffer);
+ stream->read(buffer, 256);
+ comment = std::string(buffer);
+ return true;
+ }
+
+ bool ReadExtension(std::ifstream* stream)
+ {
+ char buffer[256];
+ stream->read(buffer, 20);
+ name_english = std::string(buffer);
+ stream->read(buffer, 256);
+ comment_english = std::string(buffer);
+ return true;
+ }
+ };
+
+ class PmdVertex
+ {
+ public:
+ float position[3];
+
+ float normal[3];
+
+ float uv[2];
+
+ uint16_t bone_index[2];
+
+ uint8_t bone_weight;
+
+ bool edge_invisible;
+
+ bool Read(std::ifstream* stream)
+ {
+ stream->read((char*) position, sizeof(float) * 3);
+ stream->read((char*) normal, sizeof(float) * 3);
+ stream->read((char*) uv, sizeof(float) * 2);
+ stream->read((char*) bone_index, sizeof(uint16_t) * 2);
+ stream->read((char*) &bone_weight, sizeof(uint8_t));
+ stream->read((char*) &edge_invisible, sizeof(uint8_t));
+ return true;
+ }
+ };
+
+ class PmdMaterial
+ {
+ public:
+ float diffuse[4];
+ float power;
+ float specular[3];
+ float ambient[3];
+ uint8_t toon_index;
+ uint8_t edge_flag;
+ uint32_t index_count;
+ std::string texture_filename;
+ std::string sphere_filename;
+
+ bool Read(std::ifstream* stream)
+ {
+ char buffer[20];
+ stream->read((char*) &diffuse, sizeof(float) * 4);
+ stream->read((char*) &power, sizeof(float));
+ stream->read((char*) &specular, sizeof(float) * 3);
+ stream->read((char*) &ambient, sizeof(float) * 3);
+ stream->read((char*) &toon_index, sizeof(uint8_t));
+ stream->read((char*) &edge_flag, sizeof(uint8_t));
+ stream->read((char*) &index_count, sizeof(uint32_t));
+ stream->read((char*) &buffer, sizeof(char) * 20);
+ char* pstar = strchr(buffer, '*');
+ if (NULL == pstar)
+ {
+ texture_filename = std::string(buffer);
+ sphere_filename.clear();
+ }
+ else {
+ *pstar = 0;
+ texture_filename = std::string(buffer);
+ sphere_filename = std::string(pstar+1);
+ }
+ return true;
+ }
+ };
+
+ enum class BoneType : uint8_t
+ {
+ Rotation,
+ RotationAndMove,
+ IkEffector,
+ Unknown,
+ IkEffectable,
+ RotationEffectable,
+ IkTarget,
+ Invisible,
+ Twist,
+ RotationMovement
+ };
+
+ class PmdBone
+ {
+ public:
+ std::string name;
+ std::string name_english;
+ uint16_t parent_bone_index;
+ uint16_t tail_pos_bone_index;
+ BoneType bone_type;
+ uint16_t ik_parent_bone_index;
+ float bone_head_pos[3];
+
+ void Read(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, 20);
+ name = std::string(buffer);
+ stream->read((char*) &parent_bone_index, sizeof(uint16_t));
+ stream->read((char*) &tail_pos_bone_index, sizeof(uint16_t));
+ stream->read((char*) &bone_type, sizeof(uint8_t));
+ stream->read((char*) &ik_parent_bone_index, sizeof(uint16_t));
+ stream->read((char*) &bone_head_pos, sizeof(float) * 3);
+ }
+
+ void ReadExpantion(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, 20);
+ name_english = std::string(buffer);
+ }
+ };
+
+ class PmdIk
+ {
+ public:
+ uint16_t ik_bone_index;
+ uint16_t target_bone_index;
+ uint16_t interations;
+ float angle_limit;
+ std::vector<uint16_t> ik_child_bone_index;
+
+ void Read(std::istream *stream)
+ {
+ stream->read((char *) &ik_bone_index, sizeof(uint16_t));
+ stream->read((char *) &target_bone_index, sizeof(uint16_t));
+ uint8_t ik_chain_length;
+ stream->read((char*) &ik_chain_length, sizeof(uint8_t));
+ stream->read((char *) &interations, sizeof(uint16_t));
+ stream->read((char *) &angle_limit, sizeof(float));
+ ik_child_bone_index.resize(ik_chain_length);
+ for (int i = 0; i < ik_chain_length; i++)
+ {
+ stream->read((char *) &ik_child_bone_index[i], sizeof(uint16_t));
+ }
+ }
+ };
+
+ class PmdFaceVertex
+ {
+ public:
+ int vertex_index;
+ float position[3];
+
+ void Read(std::istream *stream)
+ {
+ stream->read((char *) &vertex_index, sizeof(int));
+ stream->read((char *) position, sizeof(float) * 3);
+ }
+ };
+
+ enum class FaceCategory : uint8_t
+ {
+ Base,
+ Eyebrow,
+ Eye,
+ Mouth,
+ Other
+ };
+
+ class PmdFace
+ {
+ public:
+ std::string name;
+ FaceCategory type;
+ std::vector<PmdFaceVertex> vertices;
+ std::string name_english;
+
+ void Read(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, 20);
+ name = std::string(buffer);
+ int vertex_count;
+ stream->read((char*) &vertex_count, sizeof(int));
+ stream->read((char*) &type, sizeof(uint8_t));
+ vertices.resize(vertex_count);
+ for (int i = 0; i < vertex_count; i++)
+ {
+ vertices[i].Read(stream);
+ }
+ }
+
+ void ReadExpantion(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, 20);
+ name_english = std::string(buffer);
+ }
+ };
+
+ class PmdBoneDispName
+ {
+ public:
+ std::string bone_disp_name;
+ std::string bone_disp_name_english;
+
+ void Read(std::istream *stream)
+ {
+ char buffer[50];
+ stream->read(buffer, 50);
+ bone_disp_name = std::string(buffer);
+ bone_disp_name_english.clear();
+ }
+ void ReadExpantion(std::istream *stream)
+ {
+ char buffer[50];
+ stream->read(buffer, 50);
+ bone_disp_name_english = std::string(buffer);
+ }
+ };
+
+ class PmdBoneDisp
+ {
+ public:
+ uint16_t bone_index;
+ uint8_t bone_disp_index;
+
+ void Read(std::istream *stream)
+ {
+ stream->read((char*) &bone_index, sizeof(uint16_t));
+ stream->read((char*) &bone_disp_index, sizeof(uint8_t));
+ }
+ };
+
+ enum class RigidBodyShape : uint8_t
+ {
+ Sphere = 0,
+ Box = 1,
+ Cpusel = 2
+ };
+
+ enum class RigidBodyType : uint8_t
+ {
+ BoneConnected = 0,
+ Physics = 1,
+ ConnectedPhysics = 2
+ };
+
+ class PmdRigidBody
+ {
+ public:
+ std::string name;
+ uint16_t related_bone_index;
+ uint8_t group_index;
+ uint16_t mask;
+ RigidBodyShape shape;
+ float size[3];
+ float position[3];
+ float orientation[3];
+ float weight;
+ float linear_damping;
+ float anglar_damping;
+ float restitution;
+ float friction;
+ RigidBodyType rigid_type;
+
+ void Read(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, sizeof(char) * 20);
+ name = (std::string(buffer));
+ stream->read((char*) &related_bone_index, sizeof(uint16_t));
+ stream->read((char*) &group_index, sizeof(uint8_t));
+ stream->read((char*) &mask, sizeof(uint16_t));
+ stream->read((char*) &shape, sizeof(uint8_t));
+ stream->read((char*) size, sizeof(float) * 3);
+ stream->read((char*) position, sizeof(float) * 3);
+ stream->read((char*) orientation, sizeof(float) * 3);
+ stream->read((char*) &weight, sizeof(float));
+ stream->read((char*) &linear_damping, sizeof(float));
+ stream->read((char*) &anglar_damping, sizeof(float));
+ stream->read((char*) &restitution, sizeof(float));
+ stream->read((char*) &friction, sizeof(float));
+ stream->read((char*) &rigid_type, sizeof(char));
+ }
+ };
+
+ class PmdConstraint
+ {
+ public:
+ std::string name;
+ uint32_t rigid_body_index_a;
+ uint32_t rigid_body_index_b;
+ float position[3];
+ float orientation[3];
+ float linear_lower_limit[3];
+ float linear_upper_limit[3];
+ float angular_lower_limit[3];
+ float angular_upper_limit[3];
+ float linear_stiffness[3];
+ float angular_stiffness[3];
+
+ void Read(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read(buffer, 20);
+ name = std::string(buffer);
+ stream->read((char *) &rigid_body_index_a, sizeof(uint32_t));
+ stream->read((char *) &rigid_body_index_b, sizeof(uint32_t));
+ stream->read((char *) position, sizeof(float) * 3);
+ stream->read((char *) orientation, sizeof(float) * 3);
+ stream->read((char *) linear_lower_limit, sizeof(float) * 3);
+ stream->read((char *) linear_upper_limit, sizeof(float) * 3);
+ stream->read((char *) angular_lower_limit, sizeof(float) * 3);
+ stream->read((char *) angular_upper_limit, sizeof(float) * 3);
+ stream->read((char *) linear_stiffness, sizeof(float) * 3);
+ stream->read((char *) angular_stiffness, sizeof(float) * 3);
+ }
+ };
+
+ class PmdModel
+ {
+ public:
+ float version;
+ PmdHeader header;
+ std::vector<PmdVertex> vertices;
+ std::vector<uint16_t> indices;
+ std::vector<PmdMaterial> materials;
+ std::vector<PmdBone> bones;
+ std::vector<PmdIk> iks;
+ std::vector<PmdFace> faces;
+ std::vector<uint16_t> faces_indices;
+ std::vector<PmdBoneDispName> bone_disp_name;
+ std::vector<PmdBoneDisp> bone_disp;
+ std::vector<std::string> toon_filenames;
+ std::vector<PmdRigidBody> rigid_bodies;
+ std::vector<PmdConstraint> constraints;
+
+ static std::unique_ptr<PmdModel> LoadFromFile(const char *filename)
+ {
+ std::ifstream stream(filename, std::ios::binary);
+ if (stream.fail())
+ {
+ std::cerr << "could not open \"" << filename << "\"" << std::endl;
+ return nullptr;
+ }
+ auto result = LoadFromStream(&stream);
+ stream.close();
+ return result;
+ }
+
+ static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream)
+ {
+ auto result = mmd::make_unique<PmdModel>();
+ char buffer[100];
+
+ // magic
+ char magic[3];
+ stream->read(magic, 3);
+ if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd')
+ {
+ std::cerr << "invalid file" << std::endl;
+ return nullptr;
+ }
+
+ // version
+ stream->read((char*) &(result->version), sizeof(float));
+ if (result ->version != 1.0f)
+ {
+ std::cerr << "invalid version" << std::endl;
+ return nullptr;
+ }
+
+ // header
+ result->header.Read(stream);
+
+ // vertices
+ uint32_t vertex_num;
+ stream->read((char*) &vertex_num, sizeof(uint32_t));
+ result->vertices.resize(vertex_num);
+ for (uint32_t i = 0; i < vertex_num; i++)
+ {
+ result->vertices[i].Read(stream);
+ }
+
+ // indices
+ uint32_t index_num;
+ stream->read((char*) &index_num, sizeof(uint32_t));
+ result->indices.resize(index_num);
+ for (uint32_t i = 0; i < index_num; i++)
+ {
+ stream->read((char*) &result->indices[i], sizeof(uint16_t));
+ }
+
+ // materials
+ uint32_t material_num;
+ stream->read((char*) &material_num, sizeof(uint32_t));
+ result->materials.resize(material_num);
+ for (uint32_t i = 0; i < material_num; i++)
+ {
+ result->materials[i].Read(stream);
+ }
+
+ // bones
+ uint16_t bone_num;
+ stream->read((char*) &bone_num, sizeof(uint16_t));
+ result->bones.resize(bone_num);
+ for (uint32_t i = 0; i < bone_num; i++)
+ {
+ result->bones[i].Read(stream);
+ }
+
+ // iks
+ uint16_t ik_num;
+ stream->read((char*) &ik_num, sizeof(uint16_t));
+ result->iks.resize(ik_num);
+ for (uint32_t i = 0; i < ik_num; i++)
+ {
+ result->iks[i].Read(stream);
+ }
+
+ // faces
+ uint16_t face_num;
+ stream->read((char*) &face_num, sizeof(uint16_t));
+ result->faces.resize(face_num);
+ for (uint32_t i = 0; i < face_num; i++)
+ {
+ result->faces[i].Read(stream);
+ }
+
+ // face frames
+ uint8_t face_frame_num;
+ stream->read((char*) &face_frame_num, sizeof(uint8_t));
+ result->faces_indices.resize(face_frame_num);
+ for (uint32_t i = 0; i < face_frame_num; i++)
+ {
+ stream->read((char*) &result->faces_indices[i], sizeof(uint16_t));
+ }
+
+ // bone names
+ uint8_t bone_disp_num;
+ stream->read((char*) &bone_disp_num, sizeof(uint8_t));
+ result->bone_disp_name.resize(bone_disp_num);
+ for (uint32_t i = 0; i < bone_disp_num; i++)
+ {
+ result->bone_disp_name[i].Read(stream);
+ }
+
+ // bone frame
+ uint32_t bone_frame_num;
+ stream->read((char*) &bone_frame_num, sizeof(uint32_t));
+ result->bone_disp.resize(bone_frame_num);
+ for (uint32_t i = 0; i < bone_frame_num; i++)
+ {
+ result->bone_disp[i].Read(stream);
+ }
+
+ // english name
+ bool english;
+ stream->read((char*) &english, sizeof(char));
+ if (english)
+ {
+ result->header.ReadExtension(stream);
+ for (uint32_t i = 0; i < bone_num; i++)
+ {
+ result->bones[i].ReadExpantion(stream);
+ }
+ for (uint32_t i = 0; i < face_num; i++)
+ {
+ if (result->faces[i].type == pmd::FaceCategory::Base)
+ {
+ continue;
+ }
+ result->faces[i].ReadExpantion(stream);
+ }
+ for (uint32_t i = 0; i < result->bone_disp_name.size(); i++)
+ {
+ result->bone_disp_name[i].ReadExpantion(stream);
+ }
+ }
+
+ // toon textures
+ if (stream->peek() == std::ios::traits_type::eof())
+ {
+ result->toon_filenames.clear();
+ }
+ else {
+ result->toon_filenames.resize(10);
+ for (uint32_t i = 0; i < 10; i++)
+ {
+ stream->read(buffer, 100);
+ result->toon_filenames[i] = std::string(buffer);
+ }
+ }
+
+ // physics
+ if (stream->peek() == std::ios::traits_type::eof())
+ {
+ result->rigid_bodies.clear();
+ result->constraints.clear();
+ }
+ else {
+ uint32_t rigid_body_num;
+ stream->read((char*) &rigid_body_num, sizeof(uint32_t));
+ result->rigid_bodies.resize(rigid_body_num);
+ for (uint32_t i = 0; i < rigid_body_num; i++)
+ {
+ result->rigid_bodies[i].Read(stream);
+ }
+ uint32_t constraint_num;
+ stream->read((char*) &constraint_num, sizeof(uint32_t));
+ result->constraints.resize(constraint_num);
+ for (uint32_t i = 0; i < constraint_num; i++)
+ {
+ result->constraints[i].Read(stream);
+ }
+ }
+
+ if (stream->peek() != std::ios::traits_type::eof())
+ {
+ std::cerr << "there is unknown data" << std::endl;
+ }
+
+ return result;
+ }
+ };
+}
diff --git a/thirdparty/assimp/code/MMD/MMDPmxParser.cpp b/thirdparty/assimp/code/MMD/MMDPmxParser.cpp
new file mode 100644
index 0000000000..80f0986dd7
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDPmxParser.cpp
@@ -0,0 +1,608 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#include <utility>
+#include "MMDPmxParser.h"
+#include <assimp/StringUtils.h>
+#ifdef ASSIMP_USE_HUNTER
+# include <utf8/utf8.h>
+#else
+# include "../contrib/utf8cpp/source/utf8.h"
+#endif
+#include <assimp/Exceptional.h>
+
+namespace pmx
+{
+ int ReadIndex(std::istream *stream, int size)
+ {
+ switch (size)
+ {
+ case 1:
+ uint8_t tmp8;
+ stream->read((char*) &tmp8, sizeof(uint8_t));
+ if (255 == tmp8)
+ {
+ return -1;
+ }
+ else {
+ return (int) tmp8;
+ }
+ case 2:
+ uint16_t tmp16;
+ stream->read((char*) &tmp16, sizeof(uint16_t));
+ if (65535 == tmp16)
+ {
+ return -1;
+ }
+ else {
+ return (int) tmp16;
+ }
+ case 4:
+ int tmp32;
+ stream->read((char*) &tmp32, sizeof(int));
+ return tmp32;
+ default:
+ return -1;
+ }
+ }
+
+ std::string ReadString(std::istream *stream, uint8_t encoding)
+ {
+ int size;
+ stream->read((char*) &size, sizeof(int));
+ std::vector<char> buffer;
+ if (size == 0)
+ {
+ return std::string("");
+ }
+ buffer.reserve(size);
+ stream->read((char*) buffer.data(), size);
+ if (encoding == 0)
+ {
+ // UTF16 to UTF8
+ const uint16_t* sourceStart = (uint16_t*)buffer.data();
+ const unsigned int targetSize = size * 3; // enough to encode
+ char *targetStart = new char[targetSize];
+ std::memset(targetStart, 0, targetSize * sizeof(char));
+
+ utf8::utf16to8( sourceStart, sourceStart + size/2, targetStart );
+
+ std::string result(targetStart);
+ delete [] targetStart;
+ return result;
+ }
+ else
+ {
+ // the name is already UTF8
+ return std::string((const char*)buffer.data(), size);
+ }
+ }
+
+ void PmxSetting::Read(std::istream *stream)
+ {
+ uint8_t count;
+ stream->read((char*) &count, sizeof(uint8_t));
+ if (count < 8)
+ {
+ throw DeadlyImportError("MMD: invalid size");
+ }
+ stream->read((char*) &encoding, sizeof(uint8_t));
+ stream->read((char*) &uv, sizeof(uint8_t));
+ stream->read((char*) &vertex_index_size, sizeof(uint8_t));
+ stream->read((char*) &texture_index_size, sizeof(uint8_t));
+ stream->read((char*) &material_index_size, sizeof(uint8_t));
+ stream->read((char*) &bone_index_size, sizeof(uint8_t));
+ stream->read((char*) &morph_index_size, sizeof(uint8_t));
+ stream->read((char*) &rigidbody_index_size, sizeof(uint8_t));
+ uint8_t temp;
+ for (int i = 8; i < count; i++)
+ {
+ stream->read((char*)&temp, sizeof(uint8_t));
+ }
+ }
+
+ void PmxVertexSkinningBDEF1::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index = ReadIndex(stream, setting->bone_index_size);
+ }
+
+ void PmxVertexSkinningBDEF2::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->bone_weight, sizeof(float));
+ }
+
+ void PmxVertexSkinningBDEF4::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index3 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index4 = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->bone_weight1, sizeof(float));
+ stream->read((char*) &this->bone_weight2, sizeof(float));
+ stream->read((char*) &this->bone_weight3, sizeof(float));
+ stream->read((char*) &this->bone_weight4, sizeof(float));
+ }
+
+ void PmxVertexSkinningSDEF::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->bone_weight, sizeof(float));
+ stream->read((char*) this->sdef_c, sizeof(float) * 3);
+ stream->read((char*) this->sdef_r0, sizeof(float) * 3);
+ stream->read((char*) this->sdef_r1, sizeof(float) * 3);
+ }
+
+ void PmxVertexSkinningQDEF::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index3 = ReadIndex(stream, setting->bone_index_size);
+ this->bone_index4 = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->bone_weight1, sizeof(float));
+ stream->read((char*) &this->bone_weight2, sizeof(float));
+ stream->read((char*) &this->bone_weight3, sizeof(float));
+ stream->read((char*) &this->bone_weight4, sizeof(float));
+ }
+
+ void PmxVertex::Read(std::istream *stream, PmxSetting *setting)
+ {
+ stream->read((char*) this->position, sizeof(float) * 3);
+ stream->read((char*) this->normal, sizeof(float) * 3);
+ stream->read((char*) this->uv, sizeof(float) * 2);
+ for (int i = 0; i < setting->uv; ++i)
+ {
+ stream->read((char*) this->uva[i], sizeof(float) * 4);
+ }
+ stream->read((char*) &this->skinning_type, sizeof(PmxVertexSkinningType));
+ switch (this->skinning_type)
+ {
+ case PmxVertexSkinningType::BDEF1:
+ this->skinning = mmd::make_unique<PmxVertexSkinningBDEF1>();
+ break;
+ case PmxVertexSkinningType::BDEF2:
+ this->skinning = mmd::make_unique<PmxVertexSkinningBDEF2>();
+ break;
+ case PmxVertexSkinningType::BDEF4:
+ this->skinning = mmd::make_unique<PmxVertexSkinningBDEF4>();
+ break;
+ case PmxVertexSkinningType::SDEF:
+ this->skinning = mmd::make_unique<PmxVertexSkinningSDEF>();
+ break;
+ case PmxVertexSkinningType::QDEF:
+ this->skinning = mmd::make_unique<PmxVertexSkinningQDEF>();
+ break;
+ default:
+ throw "invalid skinning type";
+ }
+ this->skinning->Read(stream, setting);
+ stream->read((char*) &this->edge, sizeof(float));
+ }
+
+ void PmxMaterial::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->material_name = ReadString(stream, setting->encoding);
+ this->material_english_name = ReadString(stream, setting->encoding);
+ stream->read((char*) this->diffuse, sizeof(float) * 4);
+ stream->read((char*) this->specular, sizeof(float) * 3);
+ stream->read((char*) &this->specularlity, sizeof(float));
+ stream->read((char*) this->ambient, sizeof(float) * 3);
+ stream->read((char*) &this->flag, sizeof(uint8_t));
+ stream->read((char*) this->edge_color, sizeof(float) * 4);
+ stream->read((char*) &this->edge_size, sizeof(float));
+ this->diffuse_texture_index = ReadIndex(stream, setting->texture_index_size);
+ this->sphere_texture_index = ReadIndex(stream, setting->texture_index_size);
+ stream->read((char*) &this->sphere_op_mode, sizeof(uint8_t));
+ stream->read((char*) &this->common_toon_flag, sizeof(uint8_t));
+ if (this->common_toon_flag)
+ {
+ stream->read((char*) &this->toon_texture_index, sizeof(uint8_t));
+ }
+ else {
+ this->toon_texture_index = ReadIndex(stream, setting->texture_index_size);
+ }
+ this->memo = ReadString(stream, setting->encoding);
+ stream->read((char*) &this->index_count, sizeof(int));
+ }
+
+ void PmxIkLink::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->link_target = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->angle_lock, sizeof(uint8_t));
+ if (angle_lock == 1)
+ {
+ stream->read((char*) this->max_radian, sizeof(float) * 3);
+ stream->read((char*) this->min_radian, sizeof(float) * 3);
+ }
+ }
+
+ void PmxBone::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_name = ReadString(stream, setting->encoding);
+ this->bone_english_name = ReadString(stream, setting->encoding);
+ stream->read((char*) this->position, sizeof(float) * 3);
+ this->parent_index = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->level, sizeof(int));
+ stream->read((char*) &this->bone_flag, sizeof(uint16_t));
+ if (this->bone_flag & 0x0001) {
+ this->target_index = ReadIndex(stream, setting->bone_index_size);
+ }
+ else {
+ stream->read((char*)this->offset, sizeof(float) * 3);
+ }
+ if (this->bone_flag & (0x0100 | 0x0200)) {
+ this->grant_parent_index = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->grant_weight, sizeof(float));
+ }
+ if (this->bone_flag & 0x0400) {
+ stream->read((char*)this->lock_axis_orientation, sizeof(float) * 3);
+ }
+ if (this->bone_flag & 0x0800) {
+ stream->read((char*)this->local_axis_x_orientation, sizeof(float) * 3);
+ stream->read((char*)this->local_axis_y_orientation, sizeof(float) * 3);
+ }
+ if (this->bone_flag & 0x2000) {
+ stream->read((char*) &this->key, sizeof(int));
+ }
+ if (this->bone_flag & 0x0020) {
+ this->ik_target_bone_index = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &ik_loop, sizeof(int));
+ stream->read((char*) &ik_loop_angle_limit, sizeof(float));
+ stream->read((char*) &ik_link_count, sizeof(int));
+ this->ik_links = mmd::make_unique<PmxIkLink []>(ik_link_count);
+ for (int i = 0; i < ik_link_count; i++) {
+ ik_links[i].Read(stream, setting);
+ }
+ }
+ }
+
+ void PmxMorphVertexOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->vertex_index = ReadIndex(stream, setting->vertex_index_size);
+ stream->read((char*)this->position_offset, sizeof(float) * 3);
+ }
+
+ void PmxMorphUVOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->vertex_index = ReadIndex(stream, setting->vertex_index_size);
+ stream->read((char*)this->uv_offset, sizeof(float) * 4);
+ }
+
+ void PmxMorphBoneOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->bone_index = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*)this->translation, sizeof(float) * 3);
+ stream->read((char*)this->rotation, sizeof(float) * 4);
+ }
+
+ void PmxMorphMaterialOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->material_index = ReadIndex(stream, setting->material_index_size);
+ stream->read((char*) &this->offset_operation, sizeof(uint8_t));
+ stream->read((char*)this->diffuse, sizeof(float) * 4);
+ stream->read((char*)this->specular, sizeof(float) * 3);
+ stream->read((char*) &this->specularity, sizeof(float));
+ stream->read((char*)this->ambient, sizeof(float) * 3);
+ stream->read((char*)this->edge_color, sizeof(float) * 4);
+ stream->read((char*) &this->edge_size, sizeof(float));
+ stream->read((char*)this->texture_argb, sizeof(float) * 4);
+ stream->read((char*)this->sphere_texture_argb, sizeof(float) * 4);
+ stream->read((char*)this->toon_texture_argb, sizeof(float) * 4);
+ }
+
+ void PmxMorphGroupOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->morph_index = ReadIndex(stream, setting->morph_index_size);
+ stream->read((char*) &this->morph_weight, sizeof(float));
+ }
+
+ void PmxMorphFlipOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->morph_index = ReadIndex(stream, setting->morph_index_size);
+ stream->read((char*) &this->morph_value, sizeof(float));
+ }
+
+ void PmxMorphImplusOffset::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->rigid_body_index = ReadIndex(stream, setting->rigidbody_index_size);
+ stream->read((char*) &this->is_local, sizeof(uint8_t));
+ stream->read((char*)this->velocity, sizeof(float) * 3);
+ stream->read((char*)this->angular_torque, sizeof(float) * 3);
+ }
+
+ void PmxMorph::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->morph_name = ReadString(stream, setting->encoding);
+ this->morph_english_name = ReadString(stream, setting->encoding);
+ stream->read((char*) &category, sizeof(MorphCategory));
+ stream->read((char*) &morph_type, sizeof(MorphType));
+ stream->read((char*) &this->offset_count, sizeof(int));
+ switch (this->morph_type)
+ {
+ case MorphType::Group:
+ group_offsets = mmd::make_unique<PmxMorphGroupOffset []>(this->offset_count);
+ for (int i = 0; i < offset_count; i++)
+ {
+ group_offsets[i].Read(stream, setting);
+ }
+ break;
+ case MorphType::Vertex:
+ vertex_offsets = mmd::make_unique<PmxMorphVertexOffset []>(this->offset_count);
+ for (int i = 0; i < offset_count; i++)
+ {
+ vertex_offsets[i].Read(stream, setting);
+ }
+ break;
+ case MorphType::Bone:
+ bone_offsets = mmd::make_unique<PmxMorphBoneOffset []>(this->offset_count);
+ for (int i = 0; i < offset_count; i++)
+ {
+ bone_offsets[i].Read(stream, setting);
+ }
+ break;
+ case MorphType::Matrial:
+ material_offsets = mmd::make_unique<PmxMorphMaterialOffset []>(this->offset_count);
+ for (int i = 0; i < offset_count; i++)
+ {
+ material_offsets[i].Read(stream, setting);
+ }
+ break;
+ case MorphType::UV:
+ case MorphType::AdditionalUV1:
+ case MorphType::AdditionalUV2:
+ case MorphType::AdditionalUV3:
+ case MorphType::AdditionalUV4:
+ uv_offsets = mmd::make_unique<PmxMorphUVOffset []>(this->offset_count);
+ for (int i = 0; i < offset_count; i++)
+ {
+ uv_offsets[i].Read(stream, setting);
+ }
+ break;
+ default:
+ throw DeadlyImportError("MMD: unknown morth type");
+ }
+ }
+
+ void PmxFrameElement::Read(std::istream *stream, PmxSetting *setting)
+ {
+ stream->read((char*) &this->element_target, sizeof(uint8_t));
+ if (this->element_target == 0x00)
+ {
+ this->index = ReadIndex(stream, setting->bone_index_size);
+ }
+ else {
+ this->index = ReadIndex(stream, setting->morph_index_size);
+ }
+ }
+
+ void PmxFrame::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->frame_name = ReadString(stream, setting->encoding);
+ this->frame_english_name = ReadString(stream, setting->encoding);
+ stream->read((char*) &this->frame_flag, sizeof(uint8_t));
+ stream->read((char*) &this->element_count, sizeof(int));
+ this->elements = mmd::make_unique<PmxFrameElement []>(this->element_count);
+ for (int i = 0; i < this->element_count; i++)
+ {
+ this->elements[i].Read(stream, setting);
+ }
+ }
+
+ void PmxRigidBody::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->girid_body_name = ReadString(stream, setting->encoding);
+ this->girid_body_english_name = ReadString(stream, setting->encoding);
+ this->target_bone = ReadIndex(stream, setting->bone_index_size);
+ stream->read((char*) &this->group, sizeof(uint8_t));
+ stream->read((char*) &this->mask, sizeof(uint16_t));
+ stream->read((char*) &this->shape, sizeof(uint8_t));
+ stream->read((char*) this->size, sizeof(float) * 3);
+ stream->read((char*) this->position, sizeof(float) * 3);
+ stream->read((char*) this->orientation, sizeof(float) * 3);
+ stream->read((char*) &this->mass, sizeof(float));
+ stream->read((char*) &this->move_attenuation, sizeof(float));
+ stream->read((char*) &this->rotation_attenuation, sizeof(float));
+ stream->read((char*) &this->repulsion, sizeof(float));
+ stream->read((char*) &this->friction, sizeof(float));
+ stream->read((char*) &this->physics_calc_type, sizeof(uint8_t));
+ }
+
+ void PmxJointParam::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->rigid_body1 = ReadIndex(stream, setting->rigidbody_index_size);
+ this->rigid_body2 = ReadIndex(stream, setting->rigidbody_index_size);
+ stream->read((char*) this->position, sizeof(float) * 3);
+ stream->read((char*) this->orientaiton, sizeof(float) * 3);
+ stream->read((char*) this->move_limitation_min, sizeof(float) * 3);
+ stream->read((char*) this->move_limitation_max, sizeof(float) * 3);
+ stream->read((char*) this->rotation_limitation_min, sizeof(float) * 3);
+ stream->read((char*) this->rotation_limitation_max, sizeof(float) * 3);
+ stream->read((char*) this->spring_move_coefficient, sizeof(float) * 3);
+ stream->read((char*) this->spring_rotation_coefficient, sizeof(float) * 3);
+ }
+
+ void PmxJoint::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->joint_name = ReadString(stream, setting->encoding);
+ this->joint_english_name = ReadString(stream, setting->encoding);
+ stream->read((char*) &this->joint_type, sizeof(uint8_t));
+ this->param.Read(stream, setting);
+ }
+
+ void PmxAncherRigidBody::Read(std::istream *stream, PmxSetting *setting)
+ {
+ this->related_rigid_body = ReadIndex(stream, setting->rigidbody_index_size);
+ this->related_vertex = ReadIndex(stream, setting->vertex_index_size);
+ stream->read((char*) &this->is_near, sizeof(uint8_t));
+ }
+
+ void PmxSoftBody::Read(std::istream * /*stream*/, PmxSetting * /*setting*/)
+ {
+ std::cerr << "Not Implemented Exception" << std::endl;
+ throw DeadlyImportError("MMD: Not Implemented Exception");
+ }
+
+ void PmxModel::Init()
+ {
+ this->version = 0.0f;
+ this->model_name.clear();
+ this->model_english_name.clear();
+ this->model_comment.clear();
+ this->model_english_comment.clear();
+ this->vertex_count = 0;
+ this->vertices = nullptr;
+ this->index_count = 0;
+ this->indices = nullptr;
+ this->texture_count = 0;
+ this->textures = nullptr;
+ this->material_count = 0;
+ this->materials = nullptr;
+ this->bone_count = 0;
+ this->bones = nullptr;
+ this->morph_count = 0;
+ this->morphs = nullptr;
+ this->frame_count = 0;
+ this->frames = nullptr;
+ this->rigid_body_count = 0;
+ this->rigid_bodies = nullptr;
+ this->joint_count = 0;
+ this->joints = nullptr;
+ this->soft_body_count = 0;
+ this->soft_bodies = nullptr;
+ }
+
+ void PmxModel::Read(std::istream *stream)
+ {
+ char magic[4];
+ stream->read((char*) magic, sizeof(char) * 4);
+ if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
+ {
+ std::cerr << "invalid magic number." << std::endl;
+ throw DeadlyImportError("MMD: invalid magic number.");
+ }
+ stream->read((char*) &version, sizeof(float));
+ if (version != 2.0f && version != 2.1f)
+ {
+ std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
+ throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but " + to_string(version));
+ }
+ this->setting.Read(stream);
+
+ this->model_name = ReadString(stream, setting.encoding);
+ this->model_english_name = ReadString(stream, setting.encoding);
+ this->model_comment = ReadString(stream, setting.encoding);
+ this->model_english_comment = ReadString(stream, setting.encoding);
+
+ // read vertices
+ stream->read((char*) &vertex_count, sizeof(int));
+ this->vertices = mmd::make_unique<PmxVertex []>(vertex_count);
+ for (int i = 0; i < vertex_count; i++)
+ {
+ vertices[i].Read(stream, &setting);
+ }
+
+ // read indices
+ stream->read((char*) &index_count, sizeof(int));
+ this->indices = mmd::make_unique<int []>(index_count);
+ for (int i = 0; i < index_count; i++)
+ {
+ this->indices[i] = ReadIndex(stream, setting.vertex_index_size);
+ }
+
+ // read texture names
+ stream->read((char*) &texture_count, sizeof(int));
+ this->textures = mmd::make_unique<std::string []>(texture_count);
+ for (int i = 0; i < texture_count; i++)
+ {
+ this->textures[i] = ReadString(stream, setting.encoding);
+ }
+
+ // read materials
+ stream->read((char*) &material_count, sizeof(int));
+ this->materials = mmd::make_unique<PmxMaterial []>(material_count);
+ for (int i = 0; i < material_count; i++)
+ {
+ this->materials[i].Read(stream, &setting);
+ }
+
+ // read bones
+ stream->read((char*) &this->bone_count, sizeof(int));
+ this->bones = mmd::make_unique<PmxBone []>(this->bone_count);
+ for (int i = 0; i < this->bone_count; i++)
+ {
+ this->bones[i].Read(stream, &setting);
+ }
+
+ // read morphs
+ stream->read((char*) &this->morph_count, sizeof(int));
+ this->morphs = mmd::make_unique<PmxMorph []>(this->morph_count);
+ for (int i = 0; i < this->morph_count; i++)
+ {
+ this->morphs[i].Read(stream, &setting);
+ }
+
+ // read display frames
+ stream->read((char*) &this->frame_count, sizeof(int));
+ this->frames = mmd::make_unique<PmxFrame []>(this->frame_count);
+ for (int i = 0; i < this->frame_count; i++)
+ {
+ this->frames[i].Read(stream, &setting);
+ }
+
+ // read rigid bodies
+ stream->read((char*) &this->rigid_body_count, sizeof(int));
+ this->rigid_bodies = mmd::make_unique<PmxRigidBody []>(this->rigid_body_count);
+ for (int i = 0; i < this->rigid_body_count; i++)
+ {
+ this->rigid_bodies[i].Read(stream, &setting);
+ }
+
+ // read joints
+ stream->read((char*) &this->joint_count, sizeof(int));
+ this->joints = mmd::make_unique<PmxJoint []>(this->joint_count);
+ for (int i = 0; i < this->joint_count; i++)
+ {
+ this->joints[i].Read(stream, &setting);
+ }
+ }
+}
diff --git a/thirdparty/assimp/code/MMD/MMDPmxParser.h b/thirdparty/assimp/code/MMD/MMDPmxParser.h
new file mode 100644
index 0000000000..cf523a1298
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDPmxParser.h
@@ -0,0 +1,782 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <memory>
+#include "MMDCpp14.h"
+
+namespace pmx
+{
+ class PmxSetting
+ {
+ public:
+ PmxSetting()
+ : encoding(0)
+ , uv(0)
+ , vertex_index_size(0)
+ , texture_index_size(0)
+ , material_index_size(0)
+ , bone_index_size(0)
+ , morph_index_size(0)
+ , rigidbody_index_size(0)
+ {}
+
+ uint8_t encoding;
+ uint8_t uv;
+ uint8_t vertex_index_size;
+ uint8_t texture_index_size;
+ uint8_t material_index_size;
+ uint8_t bone_index_size;
+ uint8_t morph_index_size;
+ uint8_t rigidbody_index_size;
+ void Read(std::istream *stream);
+ };
+
+ enum class PmxVertexSkinningType : uint8_t
+ {
+ BDEF1 = 0,
+ BDEF2 = 1,
+ BDEF4 = 2,
+ SDEF = 3,
+ QDEF = 4,
+ };
+
+ class PmxVertexSkinning
+ {
+ public:
+ virtual void Read(std::istream *stream, PmxSetting *setting) = 0;
+ virtual ~PmxVertexSkinning() {}
+ };
+
+ class PmxVertexSkinningBDEF1 : public PmxVertexSkinning
+ {
+ public:
+ PmxVertexSkinningBDEF1()
+ : bone_index(0)
+ {}
+
+ int bone_index;
+ void Read(std::istream *stresam, PmxSetting *setting);
+ };
+
+ class PmxVertexSkinningBDEF2 : public PmxVertexSkinning
+ {
+ public:
+ PmxVertexSkinningBDEF2()
+ : bone_index1(0)
+ , bone_index2(0)
+ , bone_weight(0.0f)
+ {}
+
+ int bone_index1;
+ int bone_index2;
+ float bone_weight;
+ void Read(std::istream *stresam, PmxSetting *setting);
+ };
+
+ class PmxVertexSkinningBDEF4 : public PmxVertexSkinning
+ {
+ public:
+ PmxVertexSkinningBDEF4()
+ : bone_index1(0)
+ , bone_index2(0)
+ , bone_index3(0)
+ , bone_index4(0)
+ , bone_weight1(0.0f)
+ , bone_weight2(0.0f)
+ , bone_weight3(0.0f)
+ , bone_weight4(0.0f)
+ {}
+
+ int bone_index1;
+ int bone_index2;
+ int bone_index3;
+ int bone_index4;
+ float bone_weight1;
+ float bone_weight2;
+ float bone_weight3;
+ float bone_weight4;
+ void Read(std::istream *stresam, PmxSetting *setting);
+ };
+
+ class PmxVertexSkinningSDEF : public PmxVertexSkinning
+ {
+ public:
+ PmxVertexSkinningSDEF()
+ : bone_index1(0)
+ , bone_index2(0)
+ , bone_weight(0.0f)
+ {
+ for (int i = 0; i < 3; ++i) {
+ sdef_c[i] = 0.0f;
+ sdef_r0[i] = 0.0f;
+ sdef_r1[i] = 0.0f;
+ }
+ }
+
+ int bone_index1;
+ int bone_index2;
+ float bone_weight;
+ float sdef_c[3];
+ float sdef_r0[3];
+ float sdef_r1[3];
+ void Read(std::istream *stresam, PmxSetting *setting);
+ };
+
+ class PmxVertexSkinningQDEF : public PmxVertexSkinning
+ {
+ public:
+ PmxVertexSkinningQDEF()
+ : bone_index1(0)
+ , bone_index2(0)
+ , bone_index3(0)
+ , bone_index4(0)
+ , bone_weight1(0.0f)
+ , bone_weight2(0.0f)
+ , bone_weight3(0.0f)
+ , bone_weight4(0.0f)
+ {}
+
+ int bone_index1;
+ int bone_index2;
+ int bone_index3;
+ int bone_index4;
+ float bone_weight1;
+ float bone_weight2;
+ float bone_weight3;
+ float bone_weight4;
+ void Read(std::istream *stresam, PmxSetting *setting);
+ };
+
+ class PmxVertex
+ {
+ public:
+ PmxVertex()
+ : edge(0.0f)
+ {
+ uv[0] = uv[1] = 0.0f;
+ for (int i = 0; i < 3; ++i) {
+ position[i] = 0.0f;
+ normal[i] = 0.0f;
+ }
+ for (int i = 0; i < 4; ++i) {
+ for (int k = 0; k < 4; ++k) {
+ uva[i][k] = 0.0f;
+ }
+ }
+ }
+
+ float position[3];
+ float normal[3];
+ float uv[2];
+ float uva[4][4];
+ PmxVertexSkinningType skinning_type;
+ std::unique_ptr<PmxVertexSkinning> skinning;
+ float edge;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxMaterial
+ {
+ public:
+ PmxMaterial()
+ : specularlity(0.0f)
+ , flag(0)
+ , edge_size(0.0f)
+ , diffuse_texture_index(0)
+ , sphere_texture_index(0)
+ , sphere_op_mode(0)
+ , common_toon_flag(0)
+ , toon_texture_index(0)
+ , index_count(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ specular[i] = 0.0f;
+ ambient[i] = 0.0f;
+ edge_color[i] = 0.0f;
+ }
+ for (int i = 0; i < 4; ++i) {
+ diffuse[i] = 0.0f;
+ }
+ }
+
+ std::string material_name;
+ std::string material_english_name;
+ float diffuse[4];
+ float specular[3];
+ float specularlity;
+ float ambient[3];
+ uint8_t flag;
+ float edge_color[4];
+ float edge_size;
+ int diffuse_texture_index;
+ int sphere_texture_index;
+ uint8_t sphere_op_mode;
+ uint8_t common_toon_flag;
+ int toon_texture_index;
+ std::string memo;
+ int index_count;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxIkLink
+ {
+ public:
+ PmxIkLink()
+ : link_target(0)
+ , angle_lock(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ max_radian[i] = 0.0f;
+ min_radian[i] = 0.0f;
+ }
+ }
+
+ int link_target;
+ uint8_t angle_lock;
+ float max_radian[3];
+ float min_radian[3];
+ void Read(std::istream *stream, PmxSetting *settingn);
+ };
+
+ class PmxBone
+ {
+ public:
+ PmxBone()
+ : parent_index(0)
+ , level(0)
+ , bone_flag(0)
+ , target_index(0)
+ , grant_parent_index(0)
+ , grant_weight(0.0f)
+ , key(0)
+ , ik_target_bone_index(0)
+ , ik_loop(0)
+ , ik_loop_angle_limit(0.0f)
+ , ik_link_count(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ position[i] = 0.0f;
+ offset[i] = 0.0f;
+ lock_axis_orientation[i] = 0.0f;
+ local_axis_x_orientation[i] = 0.0f;
+ local_axis_y_orientation[i] = 0.0f;
+ }
+ }
+
+ std::string bone_name;
+ std::string bone_english_name;
+ float position[3];
+ int parent_index;
+ int level;
+ uint16_t bone_flag;
+ float offset[3];
+ int target_index;
+ int grant_parent_index;
+ float grant_weight;
+ float lock_axis_orientation[3];
+ float local_axis_x_orientation[3];
+ float local_axis_y_orientation[3];
+ int key;
+ int ik_target_bone_index;
+ int ik_loop;
+ float ik_loop_angle_limit;
+ int ik_link_count;
+ std::unique_ptr<PmxIkLink []> ik_links;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ enum class MorphType : uint8_t
+ {
+ Group = 0,
+ Vertex = 1,
+ Bone = 2,
+ UV = 3,
+ AdditionalUV1 = 4,
+ AdditionalUV2 = 5,
+ AdditionalUV3 = 6,
+ AdditionalUV4 = 7,
+ Matrial = 8,
+ Flip = 9,
+ Implus = 10,
+ };
+
+ enum class MorphCategory : uint8_t
+ {
+ ReservedCategory = 0,
+ Eyebrow = 1,
+ Eye = 2,
+ Mouth = 3,
+ Other = 4,
+ };
+
+ class PmxMorphOffset
+ {
+ public:
+ void virtual Read(std::istream *stream, PmxSetting *setting) = 0;
+ };
+
+ class PmxMorphVertexOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphVertexOffset()
+ : vertex_index(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ position_offset[i] = 0.0f;
+ }
+ }
+ int vertex_index;
+ float position_offset[3];
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphUVOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphUVOffset()
+ : vertex_index(0)
+ {
+ for (int i = 0; i < 4; ++i) {
+ uv_offset[i] = 0.0f;
+ }
+ }
+ int vertex_index;
+ float uv_offset[4];
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphBoneOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphBoneOffset()
+ : bone_index(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ translation[i] = 0.0f;
+ }
+ for (int i = 0; i < 4; ++i) {
+ rotation[i] = 0.0f;
+ }
+ }
+ int bone_index;
+ float translation[3];
+ float rotation[4];
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphMaterialOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphMaterialOffset()
+ : specularity(0.0f)
+ , edge_size(0.0f)
+ {
+ for (int i = 0; i < 3; ++i) {
+ specular[i] = 0.0f;
+ ambient[i] = 0.0f;
+ }
+ for (int i = 0; i < 4; ++i) {
+ diffuse[i] = 0.0f;
+ edge_color[i] = 0.0f;
+ texture_argb[i] = 0.0f;
+ sphere_texture_argb[i] = 0.0f;
+ toon_texture_argb[i] = 0.0f;
+ }
+ }
+ int material_index;
+ uint8_t offset_operation;
+ float diffuse[4];
+ float specular[3];
+ float specularity;
+ float ambient[3];
+ float edge_color[4];
+ float edge_size;
+ float texture_argb[4];
+ float sphere_texture_argb[4];
+ float toon_texture_argb[4];
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphGroupOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphGroupOffset()
+ : morph_index(0)
+ , morph_weight(0.0f)
+ {}
+ int morph_index;
+ float morph_weight;
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphFlipOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphFlipOffset()
+ : morph_index(0)
+ , morph_value(0.0f)
+ {}
+ int morph_index;
+ float morph_value;
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorphImplusOffset : public PmxMorphOffset
+ {
+ public:
+ PmxMorphImplusOffset()
+ : rigid_body_index(0)
+ , is_local(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ velocity[i] = 0.0f;
+ angular_torque[i] = 0.0f;
+ }
+ }
+ int rigid_body_index;
+ uint8_t is_local;
+ float velocity[3];
+ float angular_torque[3];
+ void Read(std::istream *stream, PmxSetting *setting); //override;
+ };
+
+ class PmxMorph
+ {
+ public:
+ PmxMorph()
+ : offset_count(0)
+ {
+ }
+ std::string morph_name;
+ std::string morph_english_name;
+ MorphCategory category;
+ MorphType morph_type;
+ int offset_count;
+ std::unique_ptr<PmxMorphVertexOffset []> vertex_offsets;
+ std::unique_ptr<PmxMorphUVOffset []> uv_offsets;
+ std::unique_ptr<PmxMorphBoneOffset []> bone_offsets;
+ std::unique_ptr<PmxMorphMaterialOffset []> material_offsets;
+ std::unique_ptr<PmxMorphGroupOffset []> group_offsets;
+ std::unique_ptr<PmxMorphFlipOffset []> flip_offsets;
+ std::unique_ptr<PmxMorphImplusOffset []> implus_offsets;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxFrameElement
+ {
+ public:
+ PmxFrameElement()
+ : element_target(0)
+ , index(0)
+ {
+ }
+ uint8_t element_target;
+ int index;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxFrame
+ {
+ public:
+ PmxFrame()
+ : frame_flag(0)
+ , element_count(0)
+ {
+ }
+ std::string frame_name;
+ std::string frame_english_name;
+ uint8_t frame_flag;
+ int element_count;
+ std::unique_ptr<PmxFrameElement []> elements;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxRigidBody
+ {
+ public:
+ PmxRigidBody()
+ : target_bone(0)
+ , group(0)
+ , mask(0)
+ , shape(0)
+ , mass(0.0f)
+ , move_attenuation(0.0f)
+ , rotation_attenuation(0.0f)
+ , repulsion(0.0f)
+ , friction(0.0f)
+ , physics_calc_type(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ size[i] = 0.0f;
+ position[i] = 0.0f;
+ orientation[i] = 0.0f;
+ }
+ }
+ std::string girid_body_name;
+ std::string girid_body_english_name;
+ int target_bone;
+ uint8_t group;
+ uint16_t mask;
+ uint8_t shape;
+ float size[3];
+ float position[3];
+ float orientation[3];
+ float mass;
+ float move_attenuation;
+ float rotation_attenuation;
+ float repulsion;
+ float friction;
+ uint8_t physics_calc_type;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ enum class PmxJointType : uint8_t
+ {
+ Generic6DofSpring = 0,
+ Generic6Dof = 1,
+ Point2Point = 2,
+ ConeTwist = 3,
+ Slider = 5,
+ Hinge = 6
+ };
+
+ class PmxJointParam
+ {
+ public:
+ PmxJointParam()
+ : rigid_body1(0)
+ , rigid_body2(0)
+ {
+ for (int i = 0; i < 3; ++i) {
+ position[i] = 0.0f;
+ orientaiton[i] = 0.0f;
+ move_limitation_min[i] = 0.0f;
+ move_limitation_max[i] = 0.0f;
+ rotation_limitation_min[i] = 0.0f;
+ rotation_limitation_max[i] = 0.0f;
+ spring_move_coefficient[i] = 0.0f;
+ spring_rotation_coefficient[i] = 0.0f;
+ }
+ }
+ int rigid_body1;
+ int rigid_body2;
+ float position[3];
+ float orientaiton[3];
+ float move_limitation_min[3];
+ float move_limitation_max[3];
+ float rotation_limitation_min[3];
+ float rotation_limitation_max[3];
+ float spring_move_coefficient[3];
+ float spring_rotation_coefficient[3];
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxJoint
+ {
+ public:
+ std::string joint_name;
+ std::string joint_english_name;
+ PmxJointType joint_type;
+ PmxJointParam param;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ enum PmxSoftBodyFlag : uint8_t
+ {
+ BLink = 0x01,
+ Cluster = 0x02,
+ Link = 0x04
+ };
+
+ class PmxAncherRigidBody
+ {
+ public:
+ PmxAncherRigidBody()
+ : related_rigid_body(0)
+ , related_vertex(0)
+ , is_near(false)
+ {}
+ int related_rigid_body;
+ int related_vertex;
+ bool is_near;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxSoftBody
+ {
+ public:
+ PmxSoftBody()
+ : shape(0)
+ , target_material(0)
+ , group(0)
+ , mask(0)
+ , blink_distance(0)
+ , cluster_count(0)
+ , mass(0.0)
+ , collisioni_margin(0.0)
+ , aero_model(0)
+ , VCF(0.0f)
+ , DP(0.0f)
+ , DG(0.0f)
+ , LF(0.0f)
+ , PR(0.0f)
+ , VC(0.0f)
+ , DF(0.0f)
+ , MT(0.0f)
+ , CHR(0.0f)
+ , KHR(0.0f)
+ , SHR(0.0f)
+ , AHR(0.0f)
+ , SRHR_CL(0.0f)
+ , SKHR_CL(0.0f)
+ , SSHR_CL(0.0f)
+ , SR_SPLT_CL(0.0f)
+ , SK_SPLT_CL(0.0f)
+ , SS_SPLT_CL(0.0f)
+ , V_IT(0)
+ , P_IT(0)
+ , D_IT(0)
+ , C_IT(0)
+ , LST(0.0f)
+ , AST(0.0f)
+ , VST(0.0f)
+ , anchor_count(0)
+ , pin_vertex_count(0)
+ {}
+ std::string soft_body_name;
+ std::string soft_body_english_name;
+ uint8_t shape;
+ int target_material;
+ uint8_t group;
+ uint16_t mask;
+ PmxSoftBodyFlag flag;
+ int blink_distance;
+ int cluster_count;
+ float mass;
+ float collisioni_margin;
+ int aero_model;
+ float VCF;
+ float DP;
+ float DG;
+ float LF;
+ float PR;
+ float VC;
+ float DF;
+ float MT;
+ float CHR;
+ float KHR;
+ float SHR;
+ float AHR;
+ float SRHR_CL;
+ float SKHR_CL;
+ float SSHR_CL;
+ float SR_SPLT_CL;
+ float SK_SPLT_CL;
+ float SS_SPLT_CL;
+ int V_IT;
+ int P_IT;
+ int D_IT;
+ int C_IT;
+ float LST;
+ float AST;
+ float VST;
+ int anchor_count;
+ std::unique_ptr<PmxAncherRigidBody []> anchers;
+ int pin_vertex_count;
+ std::unique_ptr<int []> pin_vertices;
+ void Read(std::istream *stream, PmxSetting *setting);
+ };
+
+ class PmxModel
+ {
+ public:
+ PmxModel()
+ : version(0.0f)
+ , vertex_count(0)
+ , index_count(0)
+ , texture_count(0)
+ , material_count(0)
+ , bone_count(0)
+ , morph_count(0)
+ , frame_count(0)
+ , rigid_body_count(0)
+ , joint_count(0)
+ , soft_body_count(0)
+ {}
+
+ float version;
+ PmxSetting setting;
+ std::string model_name;
+ std::string model_english_name;
+ std::string model_comment;
+ std::string model_english_comment;
+ int vertex_count;
+ std::unique_ptr<PmxVertex []> vertices;
+ int index_count;
+ std::unique_ptr<int []> indices;
+ int texture_count;
+ std::unique_ptr< std::string []> textures;
+ int material_count;
+ std::unique_ptr<PmxMaterial []> materials;
+ int bone_count;
+ std::unique_ptr<PmxBone []> bones;
+ int morph_count;
+ std::unique_ptr<PmxMorph []> morphs;
+ int frame_count;
+ std::unique_ptr<PmxFrame [] > frames;
+ int rigid_body_count;
+ std::unique_ptr<PmxRigidBody []> rigid_bodies;
+ int joint_count;
+ std::unique_ptr<PmxJoint []> joints;
+ int soft_body_count;
+ std::unique_ptr<PmxSoftBody []> soft_bodies;
+ void Init();
+ void Read(std::istream *stream);
+ //static std::unique_ptr<PmxModel> ReadFromFile(const char *filename);
+ //static std::unique_ptr<PmxModel> ReadFromStream(std::istream *stream);
+ };
+}
diff --git a/thirdparty/assimp/code/MMD/MMDVmdParser.h b/thirdparty/assimp/code/MMD/MMDVmdParser.h
new file mode 100644
index 0000000000..947c3a2422
--- /dev/null
+++ b/thirdparty/assimp/code/MMD/MMDVmdParser.h
@@ -0,0 +1,376 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#include <vector>
+#include <string>
+#include <memory>
+#include <iostream>
+#include <fstream>
+#include <ostream>
+#include "MMDCpp14.h"
+
+namespace vmd
+{
+ class VmdBoneFrame
+ {
+ public:
+ std::string name;
+ int frame;
+ float position[3];
+ float orientation[4];
+ char interpolation[4][4][4];
+
+ void Read(std::istream* stream)
+ {
+ char buffer[15];
+ stream->read((char*) buffer, sizeof(char)*15);
+ name = std::string(buffer);
+ stream->read((char*) &frame, sizeof(int));
+ stream->read((char*) position, sizeof(float)*3);
+ stream->read((char*) orientation, sizeof(float)*4);
+ stream->read((char*) interpolation, sizeof(char) * 4 * 4 * 4);
+ }
+
+ void Write(std::ostream* stream)
+ {
+ stream->write((char*)name.c_str(), sizeof(char) * 15);
+ stream->write((char*)&frame, sizeof(int));
+ stream->write((char*)position, sizeof(float) * 3);
+ stream->write((char*)orientation, sizeof(float) * 4);
+ stream->write((char*)interpolation, sizeof(char) * 4 * 4 * 4);
+ }
+ };
+
+ class VmdFaceFrame
+ {
+ public:
+ std::string face_name;
+ float weight;
+ uint32_t frame;
+
+ void Read(std::istream* stream)
+ {
+ char buffer[15];
+ stream->read((char*) &buffer, sizeof(char) * 15);
+ face_name = std::string(buffer);
+ stream->read((char*) &frame, sizeof(int));
+ stream->read((char*) &weight, sizeof(float));
+ }
+
+ void Write(std::ostream* stream)
+ {
+ stream->write((char*)face_name.c_str(), sizeof(char) * 15);
+ stream->write((char*)&frame, sizeof(int));
+ stream->write((char*)&weight, sizeof(float));
+ }
+ };
+
+ class VmdCameraFrame
+ {
+ public:
+ int frame;
+ float distance;
+ float position[3];
+ float orientation[3];
+ char interpolation[6][4];
+ float angle;
+ char unknown[3];
+
+ void Read(std::istream *stream)
+ {
+ stream->read((char*) &frame, sizeof(int));
+ stream->read((char*) &distance, sizeof(float));
+ stream->read((char*) position, sizeof(float) * 3);
+ stream->read((char*) orientation, sizeof(float) * 3);
+ stream->read((char*) interpolation, sizeof(char) * 24);
+ stream->read((char*) &angle, sizeof(float));
+ stream->read((char*) unknown, sizeof(char) * 3);
+ }
+
+ void Write(std::ostream *stream)
+ {
+ stream->write((char*)&frame, sizeof(int));
+ stream->write((char*)&distance, sizeof(float));
+ stream->write((char*)position, sizeof(float) * 3);
+ stream->write((char*)orientation, sizeof(float) * 3);
+ stream->write((char*)interpolation, sizeof(char) * 24);
+ stream->write((char*)&angle, sizeof(float));
+ stream->write((char*)unknown, sizeof(char) * 3);
+ }
+ };
+
+ class VmdLightFrame
+ {
+ public:
+ int frame;
+ float color[3];
+ float position[3];
+
+ void Read(std::istream* stream)
+ {
+ stream->read((char*) &frame, sizeof(int));
+ stream->read((char*) color, sizeof(float) * 3);
+ stream->read((char*) position, sizeof(float) * 3);
+ }
+
+ void Write(std::ostream* stream)
+ {
+ stream->write((char*)&frame, sizeof(int));
+ stream->write((char*)color, sizeof(float) * 3);
+ stream->write((char*)position, sizeof(float) * 3);
+ }
+ };
+
+ class VmdIkEnable
+ {
+ public:
+ std::string ik_name;
+ bool enable;
+ };
+
+ class VmdIkFrame
+ {
+ public:
+ int frame;
+ bool display;
+ std::vector<VmdIkEnable> ik_enable;
+
+ void Read(std::istream *stream)
+ {
+ char buffer[20];
+ stream->read((char*) &frame, sizeof(int));
+ stream->read((char*) &display, sizeof(uint8_t));
+ int ik_count;
+ stream->read((char*) &ik_count, sizeof(int));
+ ik_enable.resize(ik_count);
+ for (int i = 0; i < ik_count; i++)
+ {
+ stream->read(buffer, 20);
+ ik_enable[i].ik_name = std::string(buffer);
+ stream->read((char*) &ik_enable[i].enable, sizeof(uint8_t));
+ }
+ }
+
+ void Write(std::ostream *stream)
+ {
+ stream->write((char*)&frame, sizeof(int));
+ stream->write((char*)&display, sizeof(uint8_t));
+ int ik_count = static_cast<int>(ik_enable.size());
+ stream->write((char*)&ik_count, sizeof(int));
+ for (int i = 0; i < ik_count; i++)
+ {
+ const VmdIkEnable& ik_enable = this->ik_enable.at(i);
+ stream->write(ik_enable.ik_name.c_str(), 20);
+ stream->write((char*)&ik_enable.enable, sizeof(uint8_t));
+ }
+ }
+ };
+
+ class VmdMotion
+ {
+ public:
+ std::string model_name;
+ int version;
+ std::vector<VmdBoneFrame> bone_frames;
+ std::vector<VmdFaceFrame> face_frames;
+ std::vector<VmdCameraFrame> camera_frames;
+ std::vector<VmdLightFrame> light_frames;
+ std::vector<VmdIkFrame> ik_frames;
+
+ static std::unique_ptr<VmdMotion> LoadFromFile(char const *filename)
+ {
+ std::ifstream stream(filename, std::ios::binary);
+ auto result = LoadFromStream(&stream);
+ stream.close();
+ return result;
+ }
+
+ static std::unique_ptr<VmdMotion> LoadFromStream(std::ifstream *stream)
+ {
+
+ char buffer[30];
+ auto result = mmd::make_unique<VmdMotion>();
+
+ // magic and version
+ stream->read((char*) buffer, 30);
+ if (strncmp(buffer, "Vocaloid Motion Data", 20))
+ {
+ std::cerr << "invalid vmd file." << std::endl;
+ return nullptr;
+ }
+ result->version = std::atoi(buffer + 20);
+
+ // name
+ stream->read(buffer, 20);
+ result->model_name = std::string(buffer);
+
+ // bone frames
+ int bone_frame_num;
+ stream->read((char*) &bone_frame_num, sizeof(int));
+ result->bone_frames.resize(bone_frame_num);
+ for (int i = 0; i < bone_frame_num; i++)
+ {
+ result->bone_frames[i].Read(stream);
+ }
+
+ // face frames
+ int face_frame_num;
+ stream->read((char*) &face_frame_num, sizeof(int));
+ result->face_frames.resize(face_frame_num);
+ for (int i = 0; i < face_frame_num; i++)
+ {
+ result->face_frames[i].Read(stream);
+ }
+
+ // camera frames
+ int camera_frame_num;
+ stream->read((char*) &camera_frame_num, sizeof(int));
+ result->camera_frames.resize(camera_frame_num);
+ for (int i = 0; i < camera_frame_num; i++)
+ {
+ result->camera_frames[i].Read(stream);
+ }
+
+ // light frames
+ int light_frame_num;
+ stream->read((char*) &light_frame_num, sizeof(int));
+ result->light_frames.resize(light_frame_num);
+ for (int i = 0; i < light_frame_num; i++)
+ {
+ result->light_frames[i].Read(stream);
+ }
+
+ // unknown2
+ stream->read(buffer, 4);
+
+ // ik frames
+ if (stream->peek() != std::ios::traits_type::eof())
+ {
+ int ik_num;
+ stream->read((char*) &ik_num, sizeof(int));
+ result->ik_frames.resize(ik_num);
+ for (int i = 0; i < ik_num; i++)
+ {
+ result->ik_frames[i].Read(stream);
+ }
+ }
+
+ if (stream->peek() != std::ios::traits_type::eof())
+ {
+ std::cerr << "vmd stream has unknown data." << std::endl;
+ }
+
+ return result;
+ }
+
+ bool SaveToFile(const std::u16string& /*filename*/)
+ {
+ // TODO: How to adapt u16string to string?
+ /*
+ std::ofstream stream(filename.c_str(), std::ios::binary);
+ auto result = SaveToStream(&stream);
+ stream.close();
+ return result;
+ */
+ return false;
+ }
+
+ bool SaveToStream(std::ofstream *stream)
+ {
+ std::string magic = "Vocaloid Motion Data 0002\0";
+ magic.resize(30);
+
+ // magic and version
+ stream->write(magic.c_str(), 30);
+
+ // name
+ stream->write(model_name.c_str(), 20);
+
+ // bone frames
+ const int bone_frame_num = static_cast<int>(bone_frames.size());
+ stream->write(reinterpret_cast<const char*>(&bone_frame_num), sizeof(int));
+ for (int i = 0; i < bone_frame_num; i++)
+ {
+ bone_frames[i].Write(stream);
+ }
+
+ // face frames
+ const int face_frame_num = static_cast<int>(face_frames.size());
+ stream->write(reinterpret_cast<const char*>(&face_frame_num), sizeof(int));
+ for (int i = 0; i < face_frame_num; i++)
+ {
+ face_frames[i].Write(stream);
+ }
+
+ // camera frames
+ const int camera_frame_num = static_cast<int>(camera_frames.size());
+ stream->write(reinterpret_cast<const char*>(&camera_frame_num), sizeof(int));
+ for (int i = 0; i < camera_frame_num; i++)
+ {
+ camera_frames[i].Write(stream);
+ }
+
+ // light frames
+ const int light_frame_num = static_cast<int>(light_frames.size());
+ stream->write(reinterpret_cast<const char*>(&light_frame_num), sizeof(int));
+ for (int i = 0; i < light_frame_num; i++)
+ {
+ light_frames[i].Write(stream);
+ }
+
+ // self shadow datas
+ const int self_shadow_num = 0;
+ stream->write(reinterpret_cast<const char*>(&self_shadow_num), sizeof(int));
+
+ // ik frames
+ const int ik_num = static_cast<int>(ik_frames.size());
+ stream->write(reinterpret_cast<const char*>(&ik_num), sizeof(int));
+ for (int i = 0; i < ik_num; i++)
+ {
+ ik_frames[i].Write(stream);
+ }
+
+ return true;
+ }
+ };
+}