bool PMDHandler::doLoad(Model& model, istream& stream) noexcept { PMD _pmd; if (!stream.read((char*)&_pmd.Header, sizeof(_pmd.Header))) return false; // vertex if (!stream.read((char*)&_pmd.VertexCount, sizeof(_pmd.VertexCount))) return false; if (_pmd.VertexCount > 0) { _pmd.VertexList.resize(_pmd.VertexCount); if (!stream.read((char*)&_pmd.VertexList[0], (std::streamsize)(sizeof(PMD_Vertex)* _pmd.VertexCount))) return false; } // index if (!stream.read((char*)&_pmd.IndexCount, sizeof(_pmd.IndexCount))) return false; if (_pmd.IndexCount > 0) { _pmd.IndexList.resize(_pmd.IndexCount); if (!stream.read((char*)&_pmd.IndexList[0], (std::streamsize)(sizeof(PMD_Index)* _pmd.IndexCount))) return false; } // materal if (!stream.read((char*)&_pmd.MaterialCount, sizeof(_pmd.MaterialCount))) return false; if (_pmd.MaterialCount > 0) { _pmd.MaterialList.resize(_pmd.MaterialCount); if (!stream.read((char*)&_pmd.MaterialList[0], (std::streamsize)(sizeof(PMD_Material)* _pmd.MaterialCount))) return false; } // bone if (!stream.read((char*)&_pmd.BoneCount, sizeof(_pmd.BoneCount))) return false; if (_pmd.BoneCount > 0) { _pmd.BoneList.resize(_pmd.BoneCount); if (!stream.read((char*)&_pmd.BoneList[0], (std::streamsize)(sizeof(PMD_Bone)* _pmd.BoneCount))) return false; } // IK if (!stream.read((char*)&_pmd.IkCount, sizeof(_pmd.IkCount))) return false; if (_pmd.IkCount > 0) { _pmd.IkList.resize(_pmd.IkCount); for (std::size_t i = 0; i < (std::size_t)_pmd.IkCount; i++) { if (!stream.read((char*)&_pmd.IkList[i].IK, sizeof(_pmd.IkList[i].IK))) return false; if (!stream.read((char*)&_pmd.IkList[i].Target, sizeof(_pmd.IkList[i].Target))) return false; if (!stream.read((char*)&_pmd.IkList[i].LinkCount, sizeof(_pmd.IkList[i].LinkCount))) return false; if (!stream.read((char*)&_pmd.IkList[i].LoopCount, sizeof(_pmd.IkList[i].LoopCount))) return false; if (!stream.read((char*)&_pmd.IkList[i].LimitOnce, sizeof(_pmd.IkList[i].LimitOnce))) return false; _pmd.IkList[i].LinkList.resize(_pmd.IkList[i].LinkCount); if (!stream.read((char*)&_pmd.IkList[i].LinkList[0], (std::streamsize)(sizeof(PMD_Link)* _pmd.IkList[i].LinkCount))) return false; } } // Morph if (!stream.read((char*)&_pmd.MorphCount, sizeof(_pmd.MorphCount))) return false; if (_pmd.MorphCount > 0) { _pmd.MorphList.resize(_pmd.MorphCount); for (std::size_t i = 0; i < (std::size_t)_pmd.MorphCount; i++) { if (!stream.read((char*)&_pmd.MorphList[i].Name, sizeof(_pmd.MorphList[i].Name))) return false; if (!stream.read((char*)&_pmd.MorphList[i].VertexCount, sizeof(_pmd.MorphList[i].VertexCount))) return false; if (!stream.read((char*)&_pmd.MorphList[i].Category, sizeof(_pmd.MorphList[i].Category))) return false; if (_pmd.MorphList[i].VertexCount > 0) { _pmd.MorphList[i].VertexList.resize(_pmd.MorphList[i].VertexCount); if (!stream.read((char*)&_pmd.MorphList[i].VertexList[0], (std::streamsize)(sizeof(PMD_MorphVertex)* _pmd.MorphList[i].VertexCount))) return false; } } } // frame window if (!stream.read((char*)&_pmd.FrameWindow.ExpressionListCount, sizeof(_pmd.FrameWindow.ExpressionListCount))) return false; if (_pmd.FrameWindow.ExpressionListCount > 0) { _pmd.FrameWindow.ExpressionList.resize(_pmd.FrameWindow.ExpressionListCount); if (!stream.read((char*)&_pmd.FrameWindow.ExpressionList[0], (std::streamsize)(sizeof(PMD_Expression)* _pmd.FrameWindow.ExpressionListCount))) return false; } if (!stream.read((char*)&_pmd.FrameWindow.NodeNameCount, sizeof(_pmd.FrameWindow.NodeNameCount))) return false; if (_pmd.FrameWindow.NodeNameCount > 0) { _pmd.FrameWindow.NodeNameList.resize(_pmd.FrameWindow.NodeNameCount); if (!stream.read((char*)&_pmd.FrameWindow.NodeNameList[0].Name, (std::streamsize)(sizeof(PMD_NodeName)* _pmd.FrameWindow.NodeNameCount))) return false; } if (!stream.read((char*)&_pmd.FrameWindow.BoneToNodeCount, sizeof(_pmd.FrameWindow.BoneToNodeCount))) return false; if (_pmd.FrameWindow.BoneToNodeCount > 0) { _pmd.FrameWindow.BoneToNodeList.resize(_pmd.FrameWindow.BoneToNodeCount); if (!stream.read((char*)&_pmd.FrameWindow.BoneToNodeList[0].Bone, (std::streamsize)(sizeof(PMD_BoneToNode)* _pmd.FrameWindow.BoneToNodeCount))) return false; } // description if (!stream.read((char*)&_pmd.HasDescription, sizeof(_pmd.HasDescription))) return false; if (_pmd.HasDescription) { if (!stream.read((char*)&_pmd.Description.ModelName, sizeof(_pmd.Description.ModelName))) return false; if (!stream.read((char*)&_pmd.Description.Comment, sizeof(_pmd.Description.Comment))) return false; for (PMD_BoneCount i = 0; i < _pmd.BoneCount; i++) { PMD_BoneName name; if (!stream.read((char*)&name.Name, sizeof(name))) return false; _pmd.Description.BoneName.push_back(name); } for (PMD_uint8_t i = 0; i < _pmd.FrameWindow.ExpressionListCount; i++) { PMD_MorphName name; if (!stream.read((char*)&name.Name, sizeof(name))) return false; _pmd.Description.FaceName.push_back(name); } for (PMD_uint8_t i = 0; i < _pmd.FrameWindow.NodeNameCount; i++) { PMD_NodeName name; if (!stream.read((char*)&name.Name, sizeof(name))) return false; _pmd.Description.FrameName.push_back(name); } } // toon _pmd.ToonCount = PMD_NUM_TOON; _pmd.ToonList.resize(_pmd.ToonCount); if (!stream.read((char*)&_pmd.ToonList[0].Name, (std::streamsize)(sizeof(PMD_Toon) * _pmd.ToonCount))) return false; // rigidbody if (!stream.read((char*)&_pmd.BodyCount, sizeof(_pmd.BodyCount))) return false; if (_pmd.BodyCount > 0) { _pmd.BodyList.resize(_pmd.BodyCount); if (!stream.read((char*)&_pmd.BodyList[0], (std::streamsize)(sizeof(PMD_Body)* _pmd.BodyCount))) return false; } // joint if (!stream.read((char*)&_pmd.JointCount, sizeof(_pmd.JointCount))) return false; if (_pmd.JointCount > 0) { _pmd.JointList.resize(_pmd.JointCount); if (!stream.read((char*)&_pmd.JointList[0], (std::streamsize)(sizeof(PMD_Body)* _pmd.JointCount))) return false; } for (std::size_t index = 0; index < _pmd.MaterialList.size(); index++) { auto& it = _pmd.MaterialList[index]; auto material = std::make_shared<MaterialProperty>(); material->set(MATKEY_COLOR_DIFFUSE, it.Diffuse); material->set(MATKEY_COLOR_AMBIENT, it.Ambient); material->set(MATKEY_COLOR_SPECULAR, it.Specular); material->set(MATKEY_OPACITY, it.Opacity); material->set(MATKEY_SHININESS, it.Shininess); std::string name = it.TextureName; std::string::size_type substr = name.find_first_of("*"); if (substr != std::string::npos) { name.erase(name.begin() + substr, name.end()); } material->set(MATKEY_TEXTURE_DIFFUSE(0), name); material->set(MATKEY_TEXTURE_AMBIENT(0), name); model.addMaterial(material); } PMD_Index* indices = _pmd.IndexList.data(); PMD_Vertex* vertices = _pmd.VertexList.data(); MeshPropertyPtr root = std::make_shared<MeshProperty>(); MeshPropertyPtr mesh = root; MeshPropertyPtr last = nullptr; for (std::size_t index = 0; index < _pmd.MaterialList.size(); index++) { auto& it = _pmd.MaterialList[index]; Vector3Array points; Vector3Array normals; Vector2Array texcoords; VertexWeights weights; UintArray faces; for (PMD_IndexCount i = 0; i < it.FaceVertexCount; i++, indices++) { PMD_Vertex& v = vertices[*indices]; points.push_back(v.Position); normals.push_back(v.Normal); texcoords.push_back(v.UV); faces.push_back(i); VertexWeight weight; weight.weight1 = v.Weight / 100.0; weight.weight2 = 1.0 - weight.weight1; weight.weight3 = 0.0f; weight.weight4 = 0.0f; weight.bone1 = v.Bone.Bone1; weight.bone2 = v.Bone.Bone2; weight.bone3 = 0; weight.bone4 = 0; weights.push_back(weight); } if (last == mesh) { mesh = std::make_shared<MeshProperty>(); root->addChild(mesh); } mesh->setMaterialID(index); mesh->setVertexArray(points); mesh->setNormalArray(normals); mesh->setTexcoordArray(texcoords); mesh->setWeightArray(weights); mesh->setFaceArray(faces); last = mesh; } if (_pmd.BoneCount > 0) { Bones bones; InverseKinematics iks; for (auto& it : _pmd.BoneList) { Bone bone; char inbuf[MAX_PATH + 1] = { 0 }; char outbuf[MAX_PATH + 1] = { 0 }; char *in = inbuf; char *out = outbuf; std::size_t in_size = (size_t)MAX_PATH; std::size_t out_size = (size_t)MAX_PATH; memcpy(in, it.Name.Name, sizeof(it.Name.Name)); iconv_t ic = iconv_open("GBK", "SJIS"); iconv(ic, &in, &in_size, &out, &out_size); iconv_close(ic); bone.setName(std::string(outbuf)); bone.setPosition(it.Position); bone.setParent(it.Parent); bone.setChild(it.Child); bones.push_back(bone); } for (auto& it : _pmd.IkList) { IKAttr attr; attr.IKBoneIndex = it.IK; attr.IKTargetBoneIndex = it.Target; attr.IKLimitedRadian = it.LimitOnce; attr.IKLinkCount = it.LinkCount; attr.IKLoopCount = it.LoopCount; for (auto& bone : it.LinkList) { IKChild child; child.BoneIndex = bone; child.MinimumRadian = Vector3::Zero; child.MaximumRadian = Vector3(3.14, 3.14, 3.14); child.RotateLimited = 1; attr.IKList.push_back(child); } iks.push_back(attr); } root->setInverseKinematics(iks); root->setBoneArray(bones); } model.addMesh(root); return true; }