diff options
author | sanine <sanine.not@pm.me> | 2022-04-16 11:55:09 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2022-04-16 11:55:09 -0500 |
commit | db81b925d776103326128bf629cbdda576a223e7 (patch) | |
tree | 58bea8155c686733310009f6bed7363f91fbeb9d /libs/assimp/code/AssetLib/MMD | |
parent | 55860037b14fb3893ba21cf2654c83d349cc1082 (diff) |
move 3rd-party librarys into libs/ and add built-in honeysuckle
Diffstat (limited to 'libs/assimp/code/AssetLib/MMD')
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDCpp14.h | 83 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDImporter.cpp | 368 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDImporter.h | 96 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDPmdParser.h | 597 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDPmxParser.cpp | 605 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDPmxParser.h | 782 | ||||
-rw-r--r-- | libs/assimp/code/AssetLib/MMD/MMDVmdParser.h | 376 |
7 files changed, 2907 insertions, 0 deletions
diff --git a/libs/assimp/code/AssetLib/MMD/MMDCpp14.h b/libs/assimp/code/AssetLib/MMD/MMDCpp14.h new file mode 100644 index 0000000..10d3768 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDCpp14.h @@ -0,0 +1,83 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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/libs/assimp/code/AssetLib/MMD/MMDImporter.cpp b/libs/assimp/code/AssetLib/MMD/MMDImporter.cpp new file mode 100644 index 0000000..e0e68f7 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDImporter.cpp @@ -0,0 +1,368 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 "AssetLib/MMD/MMDImporter.h" +#include "AssetLib/MMD/MMDPmdParser.h" +#include "AssetLib/MMD/MMDPmxParser.h" +#include "AssetLib/MMD/MMDVmdParser.h" +#include "PostProcessing/ConvertToLHProcess.h" + +#include <assimp/DefaultIOSystem.h> +#include <assimp/ai_assert.h> +#include <assimp/scene.h> +#include <assimp/Importer.hpp> + +#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 { + static const char *tokens[] = { "PMX " }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); +} + +// ------------------------------------------------------------------------------------------------ +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 == nullptr) { + 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/libs/assimp/code/AssetLib/MMD/MMDImporter.h b/libs/assimp/code/AssetLib/MMD/MMDImporter.h new file mode 100644 index 0000000..36f3848 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDImporter.h @@ -0,0 +1,96 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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() override; + +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 override; + +private: + //! \brief Appends the supported extension. + const aiImporterDesc* GetInfo() const override; + + //! \brief File import implementation. + void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override; + + //! \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 diff --git a/libs/assimp/code/AssetLib/MMD/MMDPmdParser.h b/libs/assimp/code/AssetLib/MMD/MMDPmdParser.h new file mode 100644 index 0000000..35e4f09 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDPmdParser.h @@ -0,0 +1,597 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 (nullptr == 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 iterations; + 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 *) &iterations, 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/libs/assimp/code/AssetLib/MMD/MMDPmxParser.cpp b/libs/assimp/code/AssetLib/MMD/MMDPmxParser.cpp new file mode 100644 index 0000000..ca37ba1 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDPmxParser.cpp @@ -0,0 +1,605 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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.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*/) + { + throw DeadlyImportError("MMD: Soft Body support is not implemented."); + } + + 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) + { + throw DeadlyImportError("MMD: Invalid magic number."); + } + stream->read((char*) &version, sizeof(float)); + if (version != 2.0f && version != 2.1f) + { + throw DeadlyImportError("MMD: Unsupported version (must be 2.0 or 2.1): ", ai_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/libs/assimp/code/AssetLib/MMD/MMDPmxParser.h b/libs/assimp/code/AssetLib/MMD/MMDPmxParser.h new file mode 100644 index 0000000..08f57f6 --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDPmxParser.h @@ -0,0 +1,782 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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/libs/assimp/code/AssetLib/MMD/MMDVmdParser.h b/libs/assimp/code/AssetLib/MMD/MMDVmdParser.h new file mode 100644 index 0000000..d5c7ded --- /dev/null +++ b/libs/assimp/code/AssetLib/MMD/MMDVmdParser.h @@ -0,0 +1,376 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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_ref = this->ik_enable.at(i); + stream->write(ik_enable_ref.ik_name.c_str(), 20); + stream->write((char *)&ik_enable_ref.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 data + 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; + } + }; +} |