Merge branch 'master' into Dependabot-GitHub-Actions

pull/4569/head
Kim Kulling 2022-07-05 20:50:28 +02:00 committed by GitHub
commit 4a5ad50828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1058 additions and 603 deletions

View File

@ -14,7 +14,8 @@ The assimp port in vcpkg is kept up to date by Microsoft team members and commun
## Install on Ubuntu ## Install on Ubuntu
You can install the Asset-Importer-Lib via apt: You can install the Asset-Importer-Lib via apt:
``` ```
sudo apt-get install assimp sudp apt-get update
sudo apt-get install libassimp-dev
``` ```
## Install pyassimp ## Install pyassimp

View File

@ -90,7 +90,7 @@ OPTION( ASSIMP_BUILD_ZLIB
) )
OPTION( ASSIMP_BUILD_ASSIMP_TOOLS OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
"If the supplementary tools for Assimp are built in addition to the library." "If the supplementary tools for Assimp are built in addition to the library."
ON OFF
) )
OPTION ( ASSIMP_BUILD_SAMPLES OPTION ( ASSIMP_BUILD_SAMPLES
"If the official samples are built as well (needs Glut)." "If the official samples are built as well (needs Glut)."

16
SECURITY.md 100644
View File

@ -0,0 +1,16 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.2.4 | :white_check_mark: |
## Reporting a Vulnerability
If you have found any security vulnerability you can contact us via
kim.kulling@googlemail.com

View File

@ -74,6 +74,8 @@ namespace XmlTag {
const char* const pid = "pid"; const char* const pid = "pid";
const char* const pindex = "pindex"; const char* const pindex = "pindex";
const char* const p1 = "p1"; const char* const p1 = "p1";
const char *const p2 = "p2";
const char *const p3 = "p3";
const char* const name = "name"; const char* const name = "name";
const char* const type = "type"; const char* const type = "type";
const char* const build = "build"; const char* const build = "build";

View File

@ -64,7 +64,7 @@ bool validateColorString(const char *color) {
return true; return true;
} }
aiFace ReadTriangle(XmlNode &node) { aiFace ReadTriangle(XmlNode &node, unsigned int &texId0, unsigned int &texId1, unsigned int &texId2) {
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
@ -73,6 +73,10 @@ aiFace ReadTriangle(XmlNode &node) {
face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string())); face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string())); face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
texId0 = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::p1).as_string()));
texId1 = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::p2).as_string()));
texId2 = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::p3).as_string()));
return face; return face;
} }
@ -412,6 +416,8 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid); bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1); bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
unsigned int texId[3];
aiFace face = ReadTriangle(currentNode, texId[0], texId[1], texId[2]);
if (hasPid && hasP1) { if (hasPid && hasP1) {
auto it = mResourcesDictionnary.find(pid); auto it = mResourcesDictionnary.find(pid);
if (it != mResourcesDictionnary.end()) { if (it != mResourcesDictionnary.end()) {
@ -420,6 +426,11 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1]; mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
} else if (it->second->getType() == ResourceType::RT_Texture2DGroup) { } else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
if (mesh->mTextureCoords[0] == nullptr) { if (mesh->mTextureCoords[0] == nullptr) {
mesh->mNumUVComponents[0] = 2;
for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
mesh->mNumUVComponents[i] = 0;
}
Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second); Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second);
const std::string name = ai_to_string(group->mTexId); const std::string name = ai_to_string(group->mTexId);
for (size_t i = 0; i < mMaterials.size(); ++i) { for (size_t i = 0; i < mMaterials.size(); ++i) {
@ -427,8 +438,9 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
mesh->mMaterialIndex = static_cast<unsigned int>(i); mesh->mMaterialIndex = static_cast<unsigned int>(i);
} }
} }
mesh->mTextureCoords[0] = new aiVector3D[group->mTex2dCoords.size()]; mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
for (unsigned int i = 0; i < group->mTex2dCoords.size(); ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
mesh->mTextureCoords[0][i] = aiVector3D(group->mTex2dCoords[i].x, group->mTex2dCoords[i].y, 0); mesh->mTextureCoords[0][i] = aiVector3D(group->mTex2dCoords[i].x, group->mTex2dCoords[i].y, 0);
} }
} }
@ -436,7 +448,6 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
} }
} }
aiFace face = ReadTriangle(currentNode);
faces.push_back(face); faces.push_back(face);
} }
} }
@ -578,11 +589,15 @@ aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basemater
} }
void XmlSerializer::StoreMaterialsInScene(aiScene *scene) { void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
if (nullptr == scene || mMaterials.empty()) { if (nullptr == scene) {
return; return;
} }
scene->mNumMaterials = static_cast<unsigned int>(mMaterials.size()); scene->mNumMaterials = static_cast<unsigned int>(mMaterials.size());
if (scene->mNumMaterials == 0) {
return;
}
scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
for (size_t i = 0; i < mMaterials.size(); ++i) { for (size_t i = 0; i < mMaterials.size(); ++i) {
scene->mMaterials[i] = mMaterials[i]; scene->mMaterials[i] = mMaterials[i];

View File

@ -621,6 +621,11 @@ struct Animation {
for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
Animation *anim = *it; Animation *anim = *it;
// Assign the first animation name to the parent if empty.
// This prevents the animation name from being lost when animations are combined
if (mName.empty()) {
mName = anim->mName;
}
CombineSingleChannelAnimationsRecursively(anim); CombineSingleChannelAnimationsRecursively(anim);
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&

View File

@ -102,6 +102,7 @@ ColladaLoader::ColladaLoader() :
mTextures(), mTextures(),
mAnims(), mAnims(),
noSkeletonMesh(false), noSkeletonMesh(false),
removeEmptyBones(false),
ignoreUpDirection(false), ignoreUpDirection(false),
useColladaName(false), useColladaName(false),
mNodeNameCounter(0) { mNodeNameCounter(0) {
@ -130,6 +131,7 @@ bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ColladaLoader::SetupProperties(const Importer *pImp) { void ColladaLoader::SetupProperties(const Importer *pImp) {
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0; ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0; useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
} }
@ -798,9 +800,10 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
// count the number of bones which influence vertices of the current submesh // count the number of bones which influence vertices of the current submesh
size_t numRemainingBones = 0; size_t numRemainingBones = 0;
for (const auto & dstBone : dstBones) { for (const auto & dstBone : dstBones) {
if (!dstBone.empty()) { if (dstBone.empty() && removeEmptyBones) {
++numRemainingBones; continue;
} }
++numRemainingBones;
} }
// create bone array and copy bone weights one by one // create bone array and copy bone weights one by one
@ -809,7 +812,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
size_t boneCount = 0; size_t boneCount = 0;
for (size_t a = 0; a < numBones; ++a) { for (size_t a = 0; a < numBones; ++a) {
// omit bones without weights // omit bones without weights
if (dstBones[a].empty()) { if (dstBones[a].empty() && removeEmptyBones) {
continue; continue;
} }

View File

@ -237,6 +237,7 @@ protected:
std::vector<aiAnimation *> mAnims; std::vector<aiAnimation *> mAnims;
bool noSkeletonMesh; bool noSkeletonMesh;
bool removeEmptyBones;
bool ignoreUpDirection; bool ignoreUpDirection;
bool useColladaName; bool useColladaName;

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -87,11 +86,6 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::s
} }
} }
// ------------------------------------------------------------------------------------------------
AnimationCurve::~AnimationCurve() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name, AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/, const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
@ -147,11 +141,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons
props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false); props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
} }
// ------------------------------------------------------------------------------------------------
AnimationCurveNode::~AnimationCurveNode() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const AnimationCurveMap &AnimationCurveNode::Curves() const { const AnimationCurveMap &AnimationCurveNode::Curves() const {
if (curves.empty()) { if (curves.empty()) {
@ -193,11 +182,6 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::s
props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true); props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
} }
// ------------------------------------------------------------------------------------------------
AnimationLayer::~AnimationLayer() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/, AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
size_t whitelist_size /*= 0*/) const { size_t whitelist_size /*= 0*/) const {
@ -279,11 +263,6 @@ AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::s
} }
} }
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack() {
// empty
}
} // namespace FBX } // namespace FBX
} // namespace Assimp } // namespace Assimp

View File

@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit static constexpr size_t NumNullRecords = 25;
const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -65,12 +65,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h> #include <stdlib.h>
#include <cstdint> #include <cstdint>
#include <iomanip> #include <iomanip>
#include <iostream>
#include <iterator> #include <iterator>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <tuple>
#include <vector>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -187,8 +184,7 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
/// This struct manages nodes which may or may not end up in the node hierarchy. /// This struct manages nodes which may or may not end up in the node hierarchy.
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released. /// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
struct FBXConverter::PotentialNode struct FBXConverter::PotentialNode {
{
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {} PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {} PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; } aiNode* operator->() { return mNode; }
@ -231,7 +227,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
if (nullptr != model) { if (nullptr != model) {
nodes_chain.clear(); nodes_chain.clear();
post_nodes_chain.clear(); post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent->mTransformation;
std::string node_name = FixNodeName(model->Name()); std::string node_name = FixNodeName(model->Name());
// even though there is only a single input node, the design of // even though there is only a single input node, the design of
// assimp (or rather: the complicated transformation chain that // assimp (or rather: the complicated transformation chain that
@ -268,7 +264,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
} }
// attach geometry // attach geometry
ConvertModel(*model, nodes_chain.back().mNode, root_node); ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
// check if there will be any child nodes // check if there will be any child nodes
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
@ -447,7 +443,7 @@ void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueNam
auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
unsigned int &i = it_pair.first->second; unsigned int &i = it_pair.first->second;
while (!it_pair.second) { while (!it_pair.second) {
i++; ++i;
std::ostringstream ext; std::ostringstream ext;
ext << name << std::setfill('0') << std::setw(3) << i; ext << name << std::setfill('0') << std::setw(3) << i;
uniqueName = ext.str(); uniqueName = ext.str();
@ -646,9 +642,8 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
bool ok;
const float zero_epsilon = ai_epsilon; const auto zero_epsilon = ai_epsilon;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -660,6 +655,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
bool ok = true;
const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok); const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
if (ok && scale_compare) { if (ok && scale_compare) {
if ((v - all_ones).SquareLength() > zero_epsilon) { if ((v - all_ones).SquareLength() > zero_epsilon) {
@ -894,18 +890,17 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
} }
} }
void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node) { void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
const std::vector<const Geometry *> &geos = model.GetGeometry(); const std::vector<const Geometry *> &geos = model.GetGeometry();
std::vector<unsigned int> meshes; std::vector<unsigned int> meshes;
meshes.reserve(geos.size()); meshes.reserve(geos.size());
for (const Geometry *geo : geos) { for (const Geometry *geo : geos) {
const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo); const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo); const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
if (mesh) { if (mesh) {
const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node); const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
} else if (line) { } else if (line) {
const std::vector<unsigned int> &indices = ConvertLine(*line, root_node); const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
@ -926,7 +921,7 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root
} }
std::vector<unsigned int> std::vector<unsigned int>
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node) { FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
MeshMap::const_iterator it = meshes_converted.find(&mesh); MeshMap::const_iterator it = meshes_converted.find(&mesh);
@ -949,13 +944,13 @@ FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *
const MatIndexArray::value_type base = mindices[0]; const MatIndexArray::value_type base = mindices[0];
for (MatIndexArray::value_type index : mindices) { for (MatIndexArray::value_type index : mindices) {
if (index != base) { if (index != base) {
return ConvertMeshMultiMaterial(mesh, model, parent, root_node); return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
} }
} }
} }
// faster code-path, just copy the data // faster code-path, just copy the data
temp.push_back(ConvertMeshSingleMaterial(mesh, model, parent, root_node)); temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
return temp; return temp;
} }
@ -1023,7 +1018,35 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
return out_mesh; return out_mesh;
} }
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, static aiSkeleton *createAiSkeleton(SkeletonBoneContainer &sbc) {
if (sbc.MeshArray.empty() || sbc.SkeletonBoneToMeshLookup.empty()) {
return nullptr;
}
aiSkeleton *skeleton = new aiSkeleton;
for (auto *mesh : sbc.MeshArray) {
auto it = sbc.SkeletonBoneToMeshLookup.find(mesh);
if (it == sbc.SkeletonBoneToMeshLookup.end()) {
continue;
}
SkeletonBoneArray *ba = it->second;
if (ba == nullptr) {
continue;
}
skeleton->mNumBones = static_cast<unsigned int>(ba->size());
skeleton->mBones = new aiSkeletonBone*[skeleton->mNumBones];
size_t index = 0;
for (auto bone : (* ba)) {
skeleton->mBones[index] = bone;
++index;
}
}
return skeleton;
}
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
aiNode *parent, aiNode *) { aiNode *parent, aiNode *) {
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
@ -1142,8 +1165,15 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
} }
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
ConvertWeights(out_mesh, mesh, parent, NO_MATERIAL_SEPARATION, nullptr); ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
} else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
SkeletonBoneContainer sbc;
ConvertWeightsToSkeleton(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr, sbc);
aiSkeleton *skeleton = createAiSkeleton(sbc);
if (skeleton != nullptr) {
mSkeletons.emplace_back(skeleton);
}
} }
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
@ -1190,7 +1220,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
} }
std::vector<unsigned int> std::vector<unsigned int>
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent,
aiNode *root_node) { aiNode *root_node) {
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
ai_assert(mindices.size()); ai_assert(mindices.size());
@ -1201,7 +1231,7 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
for (MatIndexArray::value_type index : mindices) { for (MatIndexArray::value_type index : mindices) {
if (had.find(index) == had.end()) { if (had.find(index) == had.end()) {
indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node)); indices.push_back(ConvertMeshMultiMaterial(mesh, model, absolute_transform, index, parent, root_node));
had.insert(index); had.insert(index);
} }
} }
@ -1209,9 +1239,8 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
return indices; return indices;
} }
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
MatIndexArray::value_type index, MatIndexArray::value_type index, aiNode *parent, aiNode *) {
aiNode *parent, aiNode *) {
aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
const MatIndexArray &mindices = mesh.GetMaterialIndices(); const MatIndexArray &mindices = mesh.GetMaterialIndices();
@ -1374,7 +1403,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
ConvertMaterialForMesh(out_mesh, model, mesh, index); ConvertMaterialForMesh(out_mesh, model, mesh, index);
if (process_weights) { if (process_weights) {
ConvertWeights(out_mesh, mesh, parent, index, &reverseMapping); ConvertWeights(out_mesh, mesh, absolute_transform, parent, index, &reverseMapping);
} }
std::vector<aiAnimMesh *> animMeshes; std::vector<aiAnimMesh *> animMeshes;
@ -1424,19 +1453,47 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
return static_cast<unsigned int>(mMeshes.size() - 1); return static_cast<unsigned int>(mMeshes.size() - 1);
} }
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *skeletonBone ) {
skeletonBone->mNumnWeights = bone->mNumWeights;
skeletonBone->mWeights = bone->mWeights;
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
skeletonBone->mMeshId = mesh;
skeletonBone->mNode = bone->mNode;
skeletonBone->mParent = -1;
}
void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
std::vector<unsigned int> *outputVertStartIndices, SkeletonBoneContainer &skeletonContainer) {
if (skeletonContainer.SkeletonBoneToMeshLookup.find(out) != skeletonContainer.SkeletonBoneToMeshLookup.end()) {
return;
}
ConvertWeights(out, geo, absolute_transform, parent, materialIndex, outputVertStartIndices);
skeletonContainer.MeshArray.emplace_back(out);
SkeletonBoneArray *ba = new SkeletonBoneArray;
for (size_t i = 0; i < out->mNumBones; ++i) {
aiBone *bone = out->mBones[i];
if (bone == nullptr) {
continue;
}
aiSkeletonBone *skeletonBone = new aiSkeletonBone;
copyBoneToSkeletonBone(out, bone, skeletonBone);
ba->emplace_back(skeletonBone);
}
skeletonContainer.SkeletonBoneToMeshLookup[out] = ba;
}
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
aiNode *parent, unsigned int materialIndex, aiNode *parent, unsigned int materialIndex,
std::vector<unsigned int> *outputVertStartIndices) { std::vector<unsigned int> *outputVertStartIndices) {
ai_assert(geo.DeformerSkin()); ai_assert(geo.DeformerSkin());
std::vector<size_t> out_indices; std::vector<size_t> out_indices, index_out_indices, count_out_indices;
std::vector<size_t> index_out_indices;
std::vector<size_t> count_out_indices;
const Skin &sk = *geo.DeformerSkin(); const Skin &sk = *geo.DeformerSkin();
std::vector<aiBone *> bones; std::vector<aiBone*> bones;
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
ai_assert(no_mat_check || outputVertStartIndices); ai_assert(no_mat_check || outputVertStartIndices);
@ -1496,7 +1553,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
// XXX this could be heavily simplified by collecting the bone // XXX this could be heavily simplified by collecting the bone
// data in a single step. // data in a single step.
ConvertCluster(bones, cluster, out_indices, index_out_indices, ConvertCluster(bones, cluster, out_indices, index_out_indices,
count_out_indices, parent); count_out_indices, absolute_transform, parent);
} }
bone_map.clear(); bone_map.clear();
@ -1509,25 +1566,20 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
out->mBones = nullptr; out->mBones = nullptr;
out->mNumBones = 0; out->mNumBones = 0;
return; return;
} else { }
out->mBones = new aiBone *[bones.size()]();
out->mNumBones = static_cast<unsigned int>(bones.size());
std::swap_ranges(bones.begin(), bones.end(), out->mBones); out->mBones = new aiBone *[bones.size()]();
} out->mNumBones = static_cast<unsigned int>(bones.size());
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
} }
const aiNode *GetNodeByName(aiNode *current_node) { void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
aiNode *iter = current_node;
//printf("Child count: %d", iter->mNumChildren);
return iter;
}
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, aiNode *) { std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
ai_assert(cl); // make sure cluster valid aiNode *) {
std::string deformer_name = cl->TargetNode()->Name(); ai_assert(cluster != nullptr); // make sure cluster valid
std::string deformer_name = cluster->TargetNode()->Name();
aiString bone_name = aiString(FixNodeName(deformer_name)); aiString bone_name = aiString(FixNodeName(deformer_name));
aiBone *bone = nullptr; aiBone *bone = nullptr;
@ -1540,10 +1592,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
bone = new aiBone(); bone = new aiBone();
bone->mName = bone_name; bone->mName = bone_name;
bone->mOffsetMatrix = cl->Transform(); bone->mOffsetMatrix = cluster->Transform();
// store local transform link for post processing // store local transform link for post processing
/* /*
bone->mOffsetMatrix = cl->TransformLink(); bone->mOffsetMatrix = cluster->TransformLink();
bone->mOffsetMatrix.Inverse(); bone->mOffsetMatrix.Inverse();
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
@ -1560,7 +1612,7 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
const WeightArray &weights = cl->GetWeights(); const WeightArray &weights = cluster->GetWeights();
const size_t c = index_out_indices.size(); const size_t c = index_out_indices.size();
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
@ -2605,7 +2657,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
meshMorphAnim->mNumKeys = numKeys; meshMorphAnim->mNumKeys = numKeys;
meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys]; meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
unsigned int j = 0; unsigned int j = 0;
for (auto animIt : *animData) { for (auto &animIt : *animData) {
morphKeyData *keyData = animIt.second; morphKeyData *keyData = animIt.second;
unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size()); unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
@ -3180,7 +3232,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
bool ok = false; bool ok = false;
const float zero_epsilon = ai_epsilon; const auto zero_epsilon = ai_epsilon;
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok); const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
if (ok && preRotation.SquareLength() > zero_epsilon) { if (ok && preRotation.SquareLength() > zero_epsilon) {
@ -3325,6 +3377,10 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
Keys->push_back(tnew); Keys->push_back(tnew);
Values->push_back(vnew); Values->push_back(vnew);
} }
else {
// Something broke
break;
}
tp = tnew; tp = tnew;
vp = vnew; vp = vnew;
} }
@ -3625,6 +3681,12 @@ void FBXConverter::TransferDataToScene() {
std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures); std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
} }
if (!mSkeletons.empty()) {
mSceneOut->mSkeletons = new aiSkeleton *[mSkeletons.size()];
mSceneOut->mNumSkeletons = static_cast<unsigned int>(mSkeletons.size());
std::swap_ranges(mSkeletons.begin(), mSkeletons.end(), mSceneOut->mSkeletons);
}
} }
void FBXConverter::ConvertOrphanedEmbeddedTextures() { void FBXConverter::ConvertOrphanedEmbeddedTextures() {

View File

@ -75,7 +75,18 @@ typedef std::map<int64_t, morphKeyData*> morphAnimData;
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
class MeshGeometry;
using SkeletonBoneArray = std::vector<aiSkeletonBone *>;
using SkeletonBoneToMesh = std::map<aiMesh*, SkeletonBoneArray*>;
struct SkeletonBoneContainer {
std::vector<aiMesh *> MeshArray;
SkeletonBoneToMesh SkeletonBoneToMeshLookup;
};
class Document; class Document;
/** /**
* Convert a FBX #Document to #aiScene * Convert a FBX #Document to #aiScene
* @param out Empty scene to be populated * @param out Empty scene to be populated
@ -180,12 +191,12 @@ private:
void SetupNodeMetadata(const Model& model, aiNode& nd); void SetupNodeMetadata(const Model& model, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node); void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
std::vector<unsigned int> std::vector<unsigned int>
ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node); ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node); std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
@ -194,15 +205,15 @@ private:
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent); aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
aiNode *parent, aiNode *root_node); aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> std::vector<unsigned int>
ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node); ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index, unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, MatIndexArray::value_type index,
aiNode *parent, aiNode *root_node); aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -216,14 +227,19 @@ private:
* - outputVertStartIndices is only used when a material index is specified, it gives for * - outputVertStartIndices is only used when a material index is specified, it gives for
* each output vertex the DOM index it maps to. * each output vertex the DOM index it maps to.
*/ */
void ConvertWeights(aiMesh *out, const MeshGeometry &geo, aiNode *parent = nullptr, void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent = nullptr,
unsigned int materialIndex = NO_MATERIAL_SEPARATION, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
std::vector<unsigned int> *outputVertStartIndices = nullptr); std::vector<unsigned int> *outputVertStartIndices = nullptr);
// ------------------------------------------------------------------------------------------------
void ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
aiNode *parent, unsigned int materialIndex, std::vector<unsigned int> *outputVertStartIndices,
SkeletonBoneContainer &skeletonContainer);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, aiNode *parent ); std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, aiNode *parent);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
@ -296,7 +312,8 @@ private:
void ConvertAnimationStack(const AnimationStack& st); void ConvertAnimationStack(const AnimationStack& st);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas,
const BlendShapeChannel* bsc, const AnimationCurveNode* node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
@ -445,6 +462,7 @@ private:
double anim_fps; double anim_fps;
std::vector<aiSkeleton *> mSkeletons;
aiScene* const mSceneOut; aiScene* const mSceneOut;
const FBX::Document& doc; const FBX::Document& doc;
bool mRemoveEmptyBones; bool mRemoveEmptyBones;

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -58,16 +57,14 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
: Object(id,element,name) Object(id,element,name) {
{
const Scope& sc = GetRequiredScope(element); const Scope& sc = GetRequiredScope(element);
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true); props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Deformer::~Deformer() Deformer::~Deformer()
{ {

View File

@ -67,7 +67,7 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) : LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) :
doc(doc), element(element), id(id), flags() { doc(doc), element(element), id(id), flags() {
// empty // empty
} }
@ -544,7 +544,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
ai_assert( count != 0 ); ai_assert( count != 0 );
ai_assert( count <= MAX_CLASSNAMES); ai_assert( count <= MAX_CLASSNAMES);
size_t lengths[MAX_CLASSNAMES]; size_t lengths[MAX_CLASSNAMES] = {};
const size_t c = count; const size_t c = count;
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {

View File

@ -164,7 +164,7 @@ class NodeAttribute : public Object {
public: public:
NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~NodeAttribute(); virtual ~NodeAttribute() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -180,7 +180,7 @@ class CameraSwitcher : public NodeAttribute {
public: public:
CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~CameraSwitcher(); virtual ~CameraSwitcher() = default;
int CameraID() const { int CameraID() const {
return cameraId; return cameraId;
@ -225,7 +225,7 @@ class Camera : public NodeAttribute {
public: public:
Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Camera(); virtual ~Camera() = default;
fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
@ -250,21 +250,21 @@ public:
class Null : public NodeAttribute { class Null : public NodeAttribute {
public: public:
Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Null(); virtual ~Null() = default;
}; };
/** DOM base class for FBX limb node markers attached to a node */ /** DOM base class for FBX limb node markers attached to a node */
class LimbNode : public NodeAttribute { class LimbNode : public NodeAttribute {
public: public:
LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~LimbNode(); virtual ~LimbNode() = default;
}; };
/** DOM base class for FBX lights attached to a node */ /** DOM base class for FBX lights attached to a node */
class Light : public NodeAttribute { class Light : public NodeAttribute {
public: public:
Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
virtual ~Light(); virtual ~Light() = default;
enum Type { enum Type {
Type_Point, Type_Point,
@ -690,7 +690,7 @@ using KeyValueList = std::vector<float>;
class AnimationCurve : public Object { class AnimationCurve : public Object {
public: public:
AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationCurve(); virtual ~AnimationCurve() = default;
/** get list of keyframe positions (time). /** get list of keyframe positions (time).
* Invariant: |GetKeys()| > 0 */ * Invariant: |GetKeys()| > 0 */
@ -731,7 +731,7 @@ public:
AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0); const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
virtual ~AnimationCurveNode(); virtual ~AnimationCurveNode() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -776,7 +776,7 @@ using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
class AnimationLayer : public Object { class AnimationLayer : public Object {
public: public:
AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationLayer(); virtual ~AnimationLayer() = default;
const PropertyTable& Props() const { const PropertyTable& Props() const {
ai_assert(props.get()); ai_assert(props.get());
@ -799,7 +799,7 @@ using AnimationLayerList = std::vector<const AnimationLayer*>;
class AnimationStack : public Object { class AnimationStack : public Object {
public: public:
AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
virtual ~AnimationStack(); virtual ~AnimationStack() = default;
fbx_simple_property(LocalStart, int64_t, 0L) fbx_simple_property(LocalStart, int64_t, 0L)
fbx_simple_property(LocalStop, int64_t, 0L) fbx_simple_property(LocalStop, int64_t, 0L)

View File

@ -59,14 +59,12 @@ namespace Util {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
void DOMError(const std::string& message, const Token& token) void DOMError(const std::string& message, const Token& token) {
{
throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message); throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DOMError(const std::string& message, const Element* element /*= nullptr*/) void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
{
if(element) { if(element) {
DOMError(message,element->KeyToken()); DOMError(message,element->KeyToken());
} }
@ -76,8 +74,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// print warning, do return // print warning, do return
void DOMWarning(const std::string& message, const Token& token) void DOMWarning(const std::string& message, const Token& token) {
{
if(DefaultLogger::get()) { if(DefaultLogger::get()) {
ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message); ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
} }

View File

@ -74,13 +74,11 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
template <typename T> template <typename T>
inline inline const T* ProcessSimpleConnection(const Connection& con,
const T* ProcessSimpleConnection(const Connection& con, bool is_object_property_conn,
bool is_object_property_conn, const char* name,
const char* name, const Element& element,
const Element& element, const char** propNameOut = nullptr) {
const char** propNameOut = nullptr)
{
if (is_object_property_conn && !con.PropertyName().length()) { if (is_object_property_conn && !con.PropertyName().length()) {
DOMWarning("expected incoming " + std::string(name) + DOMWarning("expected incoming " + std::string(name) +
" link to be an object-object connection, ignoring", " link to be an object-object connection, ignoring",

View File

@ -255,7 +255,7 @@ void FBXExporter::WriteBinaryHeader()
void FBXExporter::WriteBinaryFooter() void FBXExporter::WriteBinaryFooter()
{ {
outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1); outfile->Write(NULL_RECORD, NumNullRecords, 1);
outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1); outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);

View File

@ -60,6 +60,7 @@ struct ImportSettings {
readLights(true), readLights(true),
readAnimations(true), readAnimations(true),
readWeights(true), readWeights(true),
useSkeleton(false),
preservePivots(true), preservePivots(true),
optimizeEmptyAnimationCurves(true), optimizeEmptyAnimationCurves(true),
useLegacyEmbeddedTextureNaming(false), useLegacyEmbeddedTextureNaming(false),
@ -112,6 +113,11 @@ struct ImportSettings {
* Default value is true. */ * Default value is true. */
bool readWeights; bool readWeights;
/** will convert all animation data into a skeleton (experimental)
* Default value is false.
*/
bool useSkeleton;
/** preserve transformation pivots and offsets. Since these can /** preserve transformation pivots and offsets. Since these can
* not directly be represented in assimp, additional dummy * not directly be represented in assimp, additional dummy
* nodes will be generated. Note that settings this to false * nodes will be generated. Note that settings this to false

View File

@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer // Constructor to be privately used by #Importer
FBXImporter::FBXImporter() { FBXImporter::FBXImporter() :
} mSettings() {
// empty
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
FBXImporter::~FBXImporter() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader // Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer *pImp) { void FBXImporter::SetupProperties(const Importer *pImp) {
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true); mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
contents[contents.size() - 1] = 0; contents[contents.size() - 1] = 0;
const char *const begin = &*contents.begin(); const char *const begin = &*contents.begin();
// broadphase tokenizing pass in which we identify the core // broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens; TokenList tokens;
try { try {
@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
Parser parser(tokens, is_binary); Parser parser(tokens, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, settings); Document doc(parser, mSettings);
// convert the FBX DOM to aiScene // convert the FBX DOM to aiScene
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
// size relative to cm // size relative to cm
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
if (size_relative_to_cm == 0.0) if (size_relative_to_cm == 0.0) {
{
// BaseImporter later asserts that fileScale is non-zero. // BaseImporter later asserts that fileScale is non-zero.
ThrowException("The UnitScaleFactor must be non-zero"); ThrowException("The UnitScaleFactor must be non-zero");
} }

View File

@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> { class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public: public:
/// @brief The class constructor.
FBXImporter(); FBXImporter();
~FBXImporter() override;
// -------------------- /// @brief The class destructor, default implementation.
bool CanRead(const std::string &pFile, ~FBXImporter() override = default;
IOSystem *pIOHandler,
bool checkSig) const override; /// @brief Will check the file for readability.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected: protected:
// -------------------- // --------------------
@ -90,7 +91,7 @@ protected:
IOSystem *pIOHandler) override; IOSystem *pIOHandler) override;
private: private:
FBX::ImportSettings settings; FBX::ImportSettings mSettings;
}; // !class FBXImporter }; // !class FBXImporter
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -54,18 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXImportSettings.h" #include "FBXImportSettings.h"
#include "FBXDocumentUtil.h" #include "FBXDocumentUtil.h"
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) :
: Object(id, element, name) Object(id, element, name), skin() {
, skin() const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
{
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
for(const Connection* con : conns) { for(const Connection* con : conns) {
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element); const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
if(sk) { if(sk) {
@ -78,12 +74,6 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
} }
} }
// ------------------------------------------------------------------------------------------------
Geometry::~Geometry()
{
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes; return blendShapes;
@ -183,18 +173,12 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(doc.Settings().readAllLayers || index == 0) { if(doc.Settings().readAllLayers || index == 0) {
const Scope& layer = GetRequiredScope(*(*it).second); const Scope& layer = GetRequiredScope(*(*it).second);
ReadLayer(layer); ReadLayer(layer);
} } else {
else {
FBXImporter::LogWarn("ignoring additional geometry layers"); FBXImporter::LogWarn("ignoring additional geometry layers");
} }
} }
} }
// ------------------------------------------------------------------------------------------------
MeshGeometry::~MeshGeometry() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const std::vector<aiVector3D>& MeshGeometry::GetVertices() const { const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
return m_vertices; return m_vertices;

View File

@ -55,22 +55,25 @@ namespace FBX {
/** /**
* DOM base class for all kinds of FBX geometry * DOM base class for all kinds of FBX geometry
*/ */
class Geometry : public Object class Geometry : public Object {
{
public: public:
/// @brief The class constructor with all parameters.
/// @param id The id.
/// @param element
/// @param name
/// @param doc
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
virtual ~Geometry(); virtual ~Geometry() = default;
/** Get the Skin attached to this geometry or nullptr */ /// Get the Skin attached to this geometry or nullptr
const Skin* DeformerSkin() const; const Skin* DeformerSkin() const;
/** Get the BlendShape attached to this geometry or nullptr */ /// Get the BlendShape attached to this geometry or nullptr
const std::vector<const BlendShape*>& GetBlendShapes() const; const std::vector<const BlendShape*>& GetBlendShapes() const;
private: private:
const Skin* skin; const Skin* skin;
std::vector<const BlendShape*> blendShapes; std::vector<const BlendShape*> blendShapes;
}; };
typedef std::vector<int> MatIndexArray; typedef std::vector<int> MatIndexArray;
@ -79,14 +82,13 @@ typedef std::vector<int> MatIndexArray;
/** /**
* DOM class for FBX geometry of type "Mesh" * DOM class for FBX geometry of type "Mesh"
*/ */
class MeshGeometry : public Geometry class MeshGeometry : public Geometry {
{
public: public:
/** The class constructor */ /** The class constructor */
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/** The class destructor */ /** The class destructor */
virtual ~MeshGeometry(); virtual ~MeshGeometry() = default;
/** Get a list of all vertex points, non-unique*/ /** Get a list of all vertex points, non-unique*/
const std::vector<aiVector3D>& GetVertices() const; const std::vector<aiVector3D>& GetVertices() const;
@ -130,6 +132,7 @@ public:
/** Determine the face to which a particular output vertex index belongs. /** Determine the face to which a particular output vertex index belongs.
* This mapping is always unique. */ * This mapping is always unique. */
unsigned int FaceForVertexIndex( unsigned int in_index ) const; unsigned int FaceForVertexIndex( unsigned int in_index ) const;
private: private:
void ReadLayer( const Scope& layer ); void ReadLayer( const Scope& layer );
void ReadLayerElement( const Scope& layerElement ); void ReadLayerElement( const Scope& layerElement );

View File

@ -57,114 +57,65 @@ namespace FBX {
using namespace Util; using namespace Util;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name) NodeAttribute::NodeAttribute(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: Object(id,element,name) Object(id, element, name), props() {
, props() const Scope &sc = GetRequiredScope(element);
{
const Scope& sc = GetRequiredScope(element);
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
// hack on the deriving type but Null/LimbNode attributes are the only case in which // hack on the deriving type but Null/LimbNode attributes are the only case in which
// the property table is by design absent and no warning should be generated // the property table is by design absent and no warning should be generated
// for it. // for it.
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode"); const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb); props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
NodeAttribute::~NodeAttribute() CameraSwitcher::CameraSwitcher(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty const Scope &sc = GetRequiredScope(element);
} const Element *const CameraId = sc["CameraId"];
const Element *const CameraName = sc["CameraName"];
const Element *const CameraIndexName = sc["CameraIndexName"];
if (CameraId) {
// ------------------------------------------------------------------------------------------------ cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId, 0));
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
const Scope& sc = GetRequiredScope(element);
const Element* const CameraId = sc["CameraId"];
const Element* const CameraName = sc["CameraName"];
const Element* const CameraIndexName = sc["CameraIndexName"];
if(CameraId) {
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
} }
if(CameraName) { if (CameraName) {
cameraName = GetRequiredToken(*CameraName,0).StringContents(); cameraName = GetRequiredToken(*CameraName, 0).StringContents();
} }
if(CameraIndexName && CameraIndexName->Tokens().size()) { if (CameraIndexName && CameraIndexName->Tokens().size()) {
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents(); cameraIndexName = GetRequiredToken(*CameraIndexName, 0).StringContents();
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CameraSwitcher::~CameraSwitcher() Camera::Camera(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name) Light::Light(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: NodeAttribute(id,element,doc,name) NodeAttribute(id, element, doc, name) {
{
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Camera::~Camera() Null::Null(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
{ NodeAttribute(id, element, doc, name) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name) LimbNode::LimbNode(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
: NodeAttribute(id,element,doc,name) NodeAttribute(id, element, doc, name) {
{
// empty // empty
} }
} // namespace FBX
} // namespace Assimp
// ------------------------------------------------------------------------------------------------ #endif // ASSIMP_BUILD_NO_FBX_IMPORTER
Light::~Light()
{
}
// ------------------------------------------------------------------------------------------------
Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
Null::~Null()
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
: NodeAttribute(id,element,doc,name)
{
}
// ------------------------------------------------------------------------------------------------
LimbNode::~LimbNode()
{
}
}
}
#endif

View File

@ -162,12 +162,6 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
} }
// ------------------------------------------------------------------------------------------------
Element::~Element()
{
// no need to delete tokens, they are owned by the parser
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::Scope(Parser& parser,bool topLevel) Scope::Scope(Parser& parser,bool topLevel)
{ {
@ -226,12 +220,6 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
root.reset(new Scope(*this,true)); root.reset(new Scope(*this,true));
} }
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TokenPtr Parser::AdvanceToNextToken() TokenPtr Parser::AdvanceToNextToken()
{ {
@ -961,8 +949,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read an array of uints // read an array of uints
void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
{
out.resize( 0 ); out.resize( 0 );
const TokenList& tok = el.Tokens(); const TokenList& tok = el.Tokens();
if(tok.empty()) { if(tok.empty()) {
@ -1186,7 +1173,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
return result; return result;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// wrapper around ParseTokenAsString() with ParseError handling // wrapper around ParseTokenAsString() with ParseError handling
std::string ParseTokenAsString(const Token& t) std::string ParseTokenAsString(const Token& t)

View File

@ -87,7 +87,7 @@ class Element
{ {
public: public:
Element(const Token& key_token, Parser& parser); Element(const Token& key_token, Parser& parser);
~Element(); ~Element() = default;
const Scope* Compound() const { const Scope* Compound() const {
return compound.get(); return compound.get();
@ -160,7 +160,7 @@ public:
/** Parse given a token list. Does not take ownership of the tokens - /** Parse given a token list. Does not take ownership of the tokens -
* the objects must persist during the entire parser lifetime */ * the objects must persist during the entire parser lifetime */
Parser (const TokenList& tokens,bool is_binary); Parser (const TokenList& tokens,bool is_binary);
~Parser(); ~Parser() = default;
const Scope& GetRootScope() const { const Scope& GetRootScope() const {
return *root.get(); return *root.get();

View File

@ -874,7 +874,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// Batch loader used to load external models // Batch loader used to load external models
BatchLoader batch(pIOHandler); BatchLoader batch(pIOHandler);
// batch.SetBasePath(pFile); //batch.SetBasePath(pFile);
cameras.reserve(5); cameras.reserve(5);
lights.reserve(5); lights.reserve(5);

View File

@ -287,7 +287,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
if (UINT_MAX == iDefaultSurface) { if (UINT_MAX == iDefaultSurface) {
pSorted.erase(pSorted.end() - 1); pSorted.erase(pSorted.end() - 1);
} }
for (unsigned int p = 0, j = 0; j < mSurfaces->size(); ++j) { for (unsigned int j = 0; j < mSurfaces->size(); ++j) {
SortedRep &sorted = pSorted[j]; SortedRep &sorted = pSorted[j];
if (sorted.empty()) if (sorted.empty())
continue; continue;
@ -425,7 +425,6 @@ void LWOImporter::InternReadFile(const std::string &pFile,
} else { } else {
ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there"); ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there");
} }
++p;
} }
} }

View File

@ -449,6 +449,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
unsigned int iWidth, unsigned int iWidth,
unsigned int iHeight) { unsigned int iHeight) {
std::unique_ptr<aiTexture> pcNew; std::unique_ptr<aiTexture> pcNew;
if (szCurrent == nullptr) {
return;
}
// get the type of the skin // get the type of the skin
unsigned int iMasked = (unsigned int)(iType & 0xF); unsigned int iMasked = (unsigned int)(iType & 0xF);

View File

@ -151,45 +151,46 @@ namespace Grammar {
} }
static TokenType matchTokenType(const char *tokenType) { static TokenType matchTokenType(const char *tokenType) {
if (MetricType == tokenType) { const size_t len = std::strlen(tokenType);
if (0 == strncmp(MetricType, tokenType, len)) {
return MetricToken; return MetricToken;
} else if (NameType == tokenType) { } else if (0 == strncmp(NameType, tokenType, len)) {
return NameToken; return NameToken;
} else if (ObjectRefType == tokenType) { } else if (0 == strncmp(ObjectRefType, tokenType, len)) {
return ObjectRefToken; return ObjectRefToken;
} else if (MaterialRefType == tokenType) { } else if (0 == strncmp(MaterialRefType, tokenType, len)) {
return MaterialRefToken; return MaterialRefToken;
} else if (MetricKeyType == tokenType) { } else if (0 == strncmp(MetricKeyType, tokenType, len)) {
return MetricKeyToken; return MetricKeyToken;
} else if (GeometryNodeType == tokenType) { } else if (0 == strncmp(GeometryNodeType, tokenType, len)) {
return GeometryNodeToken; return GeometryNodeToken;
} else if (CameraNodeType == tokenType) { } else if (0 == strncmp(CameraNodeType, tokenType, len)) {
return CameraNodeToken; return CameraNodeToken;
} else if (LightNodeType == tokenType) { } else if (0 == strncmp(LightNodeType, tokenType, len)) {
return LightNodeToken; return LightNodeToken;
} else if (GeometryObjectType == tokenType) { } else if (0 == strncmp(GeometryObjectType, tokenType, len)) {
return GeometryObjectToken; return GeometryObjectToken;
} else if (CameraObjectType == tokenType) { } else if (0 == strncmp(CameraObjectType, tokenType, len)) {
return CameraObjectToken; return CameraObjectToken;
} else if (LightObjectType == tokenType) { } else if (0 == strncmp(LightObjectType, tokenType, len)) {
return LightObjectToken; return LightObjectToken;
} else if (TransformType == tokenType) { } else if (0 == strncmp(TransformType, tokenType, len)) {
return TransformToken; return TransformToken;
} else if (MeshType == tokenType) { } else if (0 == strncmp(MeshType, tokenType, len)) {
return MeshToken; return MeshToken;
} else if (VertexArrayType == tokenType) { } else if (0 == strncmp(VertexArrayType, tokenType, len)) {
return VertexArrayToken; return VertexArrayToken;
} else if (IndexArrayType == tokenType) { } else if (0 == strncmp(IndexArrayType, tokenType, len)) {
return IndexArrayToken; return IndexArrayToken;
} else if (MaterialType == tokenType) { } else if (0 == strncmp(MaterialType, tokenType, len)) {
return MaterialToken; return MaterialToken;
} else if (ColorType == tokenType) { } else if (0 == strncmp(ColorType, tokenType, len)) {
return ColorToken; return ColorToken;
} else if (ParamType == tokenType) { } else if (0 == strncmp(ParamType, tokenType, len)) {
return ParamToken; return ParamToken;
} else if (TextureType == tokenType) { } else if (0 == strncmp(TextureType, tokenType, len)) {
return TextureToken; return TextureToken;
} else if (AttenType == tokenType) { } else if (0 == strncmp(AttenType, tokenType, len)) {
return AttenToken; return AttenToken;
} }
@ -256,11 +257,6 @@ OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::stri
// empty // empty
} }
//------------------------------------------------------------------------------------------------
OpenGEXImporter::RefInfo::~RefInfo() {
// empty
}
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
OpenGEXImporter::OpenGEXImporter() : OpenGEXImporter::OpenGEXImporter() :
m_root(nullptr), m_root(nullptr),
@ -285,10 +281,6 @@ OpenGEXImporter::OpenGEXImporter() :
// empty // empty
} }
//------------------------------------------------------------------------------------------------
OpenGEXImporter::~OpenGEXImporter() {
}
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const { bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" }; static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };

View File

@ -79,12 +79,7 @@ struct MetricInfo {
float m_floatValue; float m_floatValue;
int m_intValue; int m_intValue;
MetricInfo() MetricInfo(): m_stringValue( ), m_floatValue( 0.0f ), m_intValue( -1 ) {}
: m_stringValue( )
, m_floatValue( 0.0f )
, m_intValue( -1 ) {
// empty
}
}; };
/** @brief This class is used to implement the OpenGEX importer /** @brief This class is used to implement the OpenGEX importer
@ -97,7 +92,7 @@ public:
OpenGEXImporter(); OpenGEXImporter();
/// The class destructor. /// The class destructor.
~OpenGEXImporter() override; ~OpenGEXImporter() override = default;
/// BaseImporter override. /// BaseImporter override.
bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const override; bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const override;
@ -170,7 +165,7 @@ private:
std::vector<std::string> m_Names; std::vector<std::string> m_Names;
RefInfo( aiNode *node, Type type, std::vector<std::string> &names ); RefInfo( aiNode *node, Type type, std::vector<std::string> &names );
~RefInfo(); ~RefInfo() = default;
RefInfo( const RefInfo & ) = delete; RefInfo( const RefInfo & ) = delete;
RefInfo &operator = ( const RefInfo & ) = delete; RefInfo &operator = ( const RefInfo & ) = delete;

View File

@ -683,7 +683,7 @@ bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &she
} }
// Default Sheen color factor {0,0,0} disables Sheen, so do not export // Default Sheen color factor {0,0,0} disables Sheen, so do not export
if (sheen.sheenColorFactor == defaultSheenFactor) { if (sheen.sheenColorFactor[0] == defaultSheenFactor[0] && sheen.sheenColorFactor[1] == defaultSheenFactor[1] && sheen.sheenColorFactor[2] == defaultSheenFactor[2]) {
return false; return false;
} }
@ -908,7 +908,7 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
do { do {
startNodeRef = parentNodeRef; startNodeRef = parentNodeRef;
parentNodeRef = startNodeRef->parent; parentNodeRef = startNodeRef->parent;
} while (!parentNodeRef->jointName.empty()); } while (parentNodeRef && !parentNodeRef->jointName.empty());
return parentNodeRef; return parentNodeRef;
} }

View File

@ -63,7 +63,7 @@ inline int select_fseek(FILE *file, int64_t offset, int origin) {
#if defined _WIN64 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) #if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
template <> template <>
inline size_t select_ftell<8>(FILE *file) { inline size_t select_ftell<8>(FILE *file) {
return (size_t)::_ftelli64(file); return (size_t)::_ftelli64(file);
@ -74,7 +74,7 @@ inline int select_fseek<8>(FILE *file, int64_t offset, int origin) {
return ::_fseeki64(file, offset, origin); return ::_fseeki64(file, offset, origin);
} }
#endif // #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) #endif
} // namespace } // namespace
@ -149,13 +149,20 @@ size_t DefaultIOStream::FileSize() const {
// //
// See here for details: // See here for details:
// https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
#if defined _WIN64 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) #if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
struct __stat64 fileStat; struct __stat64 fileStat;
//using fileno + fstat avoids having to handle the filename //using fileno + fstat avoids having to handle the filename
int err = _fstat64(_fileno(mFile), &fileStat); int err = _fstat64(_fileno(mFile), &fileStat);
if (0 != err) if (0 != err)
return 0; return 0;
mCachedSize = (size_t)(fileStat.st_size); mCachedSize = (size_t)(fileStat.st_size);
#elif defined _WIN32
struct _stat32 fileStat;
//using fileno + fstat avoids having to handle the filename
int err = _fstat32(_fileno(mFile), &fileStat);
if (0 != err)
return 0;
mCachedSize = (size_t)(fileStat.st_size);
#elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__ #elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__
struct stat fileStat; struct stat fileStat;
int err = stat(mFilename.c_str(), &fileStat); int err = stat(mFilename.c_str(), &fileStat);

View File

@ -105,36 +105,39 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
if (!mesh->mTextureCoords[i]) { if (!mesh->mTextureCoords[i]) {
mesh->mNumUVComponents[i] = 0; mesh->mNumUVComponents[i] = 0;
} else { continue;
if (!mesh->mNumUVComponents[i]) { }
mesh->mNumUVComponents[i] = 2;
if (!mesh->mNumUVComponents[i]) {
mesh->mNumUVComponents[i] = 2;
}
aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
// Ensure unused components are zeroed. This will make 1D texture channels work
// as if they were 2D channels .. just in case an application doesn't handle
// this case
if (2 == mesh->mNumUVComponents[i]) {
size_t num = 0;
for (; p != end; ++p) {
p->z = 0.f;
num++;
} }
} else if (1 == mesh->mNumUVComponents[i]) {
aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices; for (; p != end; ++p) {
p->z = p->y = 0.f;
// Ensure unused components are zeroed. This will make 1D texture channels work }
// as if they were 2D channels .. just in case an application doesn't handle } else if (3 == mesh->mNumUVComponents[i]) {
// this case // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
if (2 == mesh->mNumUVComponents[i]) { for (; p != end; ++p) {
for (; p != end; ++p) { if (p->z != 0) {
p->z = 0.f; break;
}
} else if (1 == mesh->mNumUVComponents[i]) {
for (; p != end; ++p) {
p->z = p->y = 0.f;
}
} else if (3 == mesh->mNumUVComponents[i]) {
// Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
for (; p != end; ++p) {
if (p->z != 0) {
break;
}
}
if (p == end) {
ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
mesh->mNumUVComponents[i] = 2;
} }
} }
if (p == end) {
ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
mesh->mNumUVComponents[i] = 2;
}
} }
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation; const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4); aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
ai_real distanceToChild = childpos.Length(); ai_real distanceToChild = childpos.Length();
if (distanceToChild < 0.0001) if (distanceToChild < ai_epsilon) {
continue; continue;
}
aiVector3D up = aiVector3D(childpos).Normalize(); aiVector3D up = aiVector3D(childpos).Normalize();
aiVector3D orth(1.0, 0.0, 0.0); aiVector3D orth(1.0, 0.0, 0.0);
if (std::fabs(orth * up) > 0.99) if (std::fabs(orth * up) > 0.99) {
orth.Set(0.0, 1.0, 0.0); orth.Set(0.0, 1.0, 0.0);
}
aiVector3D front = (up ^ orth).Normalize(); aiVector3D front = (up ^ orth).Normalize();
aiVector3D side = (front ^ up).Normalize(); aiVector3D side = (front ^ up).Normalize();
@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
// add all the vertices to the bone's influences // add all the vertices to the bone's influences
bone->mNumWeights = numVertices; bone->mNumWeights = numVertices;
bone->mWeights = new aiVertexWeight[numVertices]; bone->mWeights = new aiVertexWeight[numVertices];
for (unsigned int a = 0; a < numVertices; a++) for (unsigned int a = 0; a < numVertices; ++a) {
bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0); bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
}
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
// them to the array, but I'm tired now and I'm annoyed. // them to the array, but I'm tired now and I'm annoyed.
@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
} }
// and finally recurse into the children list // and finally recurse into the children list
for (unsigned int a = 0; a < pNode->mNumChildren; a++) for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
CreateGeometry(pNode->mChildren[a]); CreateGeometry(pNode->mChildren[a]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -135,6 +135,9 @@ ASSIMP_API aiScene::aiScene() :
mNumCameras(0), mNumCameras(0),
mCameras(nullptr), mCameras(nullptr),
mMetaData(nullptr), mMetaData(nullptr),
mName(),
mNumSkeletons(0),
mSkeletons(nullptr),
mPrivate(new Assimp::ScenePrivateData()) { mPrivate(new Assimp::ScenePrivateData()) {
// empty // empty
} }
@ -180,7 +183,8 @@ ASSIMP_API aiScene::~aiScene() {
delete[] mCameras; delete[] mCameras;
aiMetadata::Dealloc(mMetaData); aiMetadata::Dealloc(mMetaData);
mMetaData = nullptr;
delete[] mSkeletons;
delete static_cast<Assimp::ScenePrivateData *>(mPrivate); delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
} }

View File

@ -128,7 +128,7 @@ bool EmbedTexturesProcess::addTexture(aiScene *pScene, const std::string &path)
aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)]; aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
pFile->Seek(0, aiOrigin_SET); pFile->Seek(0, aiOrigin_SET);
pFile->Read(reinterpret_cast<char*>(imageContent), imageSize, 1); pFile->Read(reinterpret_cast<char*>(imageContent), static_cast<size_t>(imageSize), 1);
mIOHandler->Close(pFile); mIOHandler->Close(pFile);
// Enlarging the textures table // Enlarging the textures table

View File

@ -1,5 +1,9 @@
#include "revision.h" #include "revision.h"
#ifdef __GNUC__
#include "winresrc.h"
#else
#include "winres.h" #include "winres.h"
#endif
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
#pragma code_page(1252) #pragma code_page(1252)

View File

@ -43,10 +43,10 @@
#include "crypt.h" #include "crypt.h"
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4244) # pragma warning(disable : 4244)
#endif // _WIN32 #endif // _MSC_VER
/***************************************************************************/ /***************************************************************************/
@ -164,8 +164,8 @@ int crypthead(const char *passwd, uint8_t *buf, int buf_size, uint32_t *pkeys,
return n; return n;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER
/***************************************************************************/ /***************************************************************************/

View File

@ -23,8 +23,10 @@
#ifdef _WIN32 #ifdef _WIN32
# define snprintf _snprintf # define snprintf _snprintf
#ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4131 4100) # pragma warning(disable : 4131 4100)
#endif
# ifdef __clang__ # ifdef __clang__
# pragma clang diagnostic push # pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-parameter" # pragma clang diagnostic ignored "-Wunused-parameter"
@ -357,9 +359,9 @@ void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
pzlib_filefunc_def->opaque = NULL; pzlib_filefunc_def->opaque = NULL;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
# ifdef __clang__ # ifdef __clang__
# pragma clang diagnostic pop # pragma clang diagnostic pop
# endif # endif
#endif // _WIN32 #endif // _MSC_VER

View File

@ -73,10 +73,10 @@
# define TRYFREE(p) {if (p) free(p);} # define TRYFREE(p) {if (p) free(p);}
#endif #endif
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable : 4131 4244 4189 4245) # pragma warning(disable : 4131 4244 4189 4245)
#endif // _WIN32 #endif // _MSC_VER
const char unz_copyright[] = const char unz_copyright[] =
" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
@ -1995,6 +1995,6 @@ extern int ZEXPORT unzEndOfFile(unzFile file)
return 0; return 0;
} }
#ifdef _WIN32 #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif // _WIN32 #endif // _MSC_VER

View File

@ -99,295 +99,129 @@ template <class TNodeType>
class TXmlParser { class TXmlParser {
public: public:
/// @brief The default class constructor. /// @brief The default class constructor.
TXmlParser() : TXmlParser();
mDoc(nullptr),
mData() {
// empty
}
/// @brief The class destructor. /// @brief The class destructor.
~TXmlParser() { ~TXmlParser();
clear();
}
/// @brief Will clear the parsed xml-file. /// @brief Will clear the parsed xml-file.
void clear() { void clear();
if (mData.empty()) {
mDoc = nullptr;
return;
}
mData.clear();
delete mDoc;
mDoc = nullptr;
}
/// @brief Will search for a child-node by its name /// @brief Will search for a child-node by its name
/// @param name [in] The name of the child-node. /// @param name [in] The name of the child-node.
/// @return The node instance or nullptr, if nothing was found. /// @return The node instance or nullptr, if nothing was found.
TNodeType *findNode(const std::string &name) { TNodeType *findNode(const std::string &name);
if (name.empty()) {
return nullptr;
}
if (nullptr == mDoc) {
return nullptr;
}
find_node_by_name_predicate predicate(name);
mCurrent = mDoc->find_node(predicate);
if (mCurrent.empty()) {
return nullptr;
}
return &mCurrent;
}
/// @brief Will return true, if the node is a child-node. /// @brief Will return true, if the node is a child-node.
/// @param name [in] The name of the child node to look for. /// @param name [in] The name of the child node to look for.
/// @return true, if the node is a child-node or false if not. /// @return true, if the node is a child-node or false if not.
bool hasNode(const std::string &name) { bool hasNode(const std::string &name);
return nullptr != findNode(name);
}
/// @brief Will parse an xml-file from a given stream. /// @brief Will parse an xml-file from a given stream.
/// @param stream The input stream. /// @param stream The input stream.
/// @return true, if the parsing was successful, false if not. /// @return true, if the parsing was successful, false if not.
bool parse(IOStream *stream) { bool parse(IOStream *stream);
if (nullptr == stream) {
ASSIMP_LOG_DEBUG("Stream is nullptr.");
return false;
}
const size_t len = stream->FileSize(); /// @brief Will return true if a root node is there.
mData.resize(len + 1);
memset(&mData[0], '\0', len + 1);
stream->Read(&mData[0], 1, len);
mDoc = new pugi::xml_document();
pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full);
if (parse_result.status == pugi::status_ok) {
return true;
}
ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
return false;
}
/// @brief Will return truem if a root node is there.
/// @return true in case of an existing root. /// @return true in case of an existing root.
bool hasRoot() const { bool hasRoot() const;
return nullptr != mDoc;
}
/// @brief Will return the document pointer, is nullptr if no xml-file was parsed. /// @brief Will return the document pointer, is nullptr if no xml-file was parsed.
/// @return The pointer showing to the document. /// @return The pointer showing to the document.
pugi::xml_document *getDocument() const { pugi::xml_document *getDocument() const;
return mDoc;
}
/// @brief Will return the root node, const version. /// @brief Will return the root node, const version.
/// @return The root node. /// @return The root node.
const TNodeType getRootNode() const { const TNodeType getRootNode() const;
static pugi::xml_node none;
if (nullptr == mDoc) {
return none;
}
return mDoc->root();
}
/// @brief Will return the root node, non-const version. /// @brief Will return the root node, non-const version.
/// @return The root node. /// @return The root node.
TNodeType getRootNode() { TNodeType getRootNode();
static pugi::xml_node none;
if (nullptr == mDoc) {
return none;
}
return mDoc->root();
}
/// @brief Will check if a node with the given name is in. /// @brief Will check if a node with the given name is in.
/// @param node [in] The node to look in. /// @param node [in] The node to look in.
/// @param name [in] The name of the child-node. /// @param name [in] The name of the child-node.
/// @return true, if node was found, false if not. /// @return true, if node was found, false if not.
static inline bool hasNode(XmlNode &node, const char *name) { static inline bool hasNode(XmlNode &node, const char *name);
pugi::xml_node child = node.find_child(find_node_by_name_predicate(name));
return !child.empty();
}
/// @brief Will check if an attribute is part of the XmlNode. /// @brief Will check if an attribute is part of the XmlNode.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in} The attribute name to look for. /// @param name [in} The attribute name to look for.
/// @return true, if the was found, false if not. /// @return true, if the was found, false if not.
static inline bool hasAttribute(XmlNode &xmlNode, const char *name) { static inline bool hasAttribute(XmlNode &xmlNode, const char *name);
pugi::xml_attribute attr = xmlNode.attribute(name);
return !attr.empty();
}
/// @brief Will try to get an unsigned int attribute value. /// @brief Will try to get an unsigned int attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The unsigned int value from the attribute. /// @param val [out] The unsigned int value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is an unsigned int. /// @return true, if the node contains an attribute with the given name and if the value is an unsigned int.
static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) { static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_uint();
return true;
}
/// @brief Will try to get an int attribute value. /// @brief Will try to get an int attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The int value from the attribute. /// @param val [out] The int value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is an int. /// @return true, if the node contains an attribute with the given name and if the value is an int.
static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val) { static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_int();
return true;
}
/// @brief Will try to get a real attribute value. /// @brief Will try to get a real attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The real value from the attribute. /// @param val [out] The real value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a real. /// @return true, if the node contains an attribute with the given name and if the value is a real.
static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) { static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
#ifdef ASSIMP_DOUBLE_PRECISION
val = attr.as_double();
#else
val = attr.as_float();
#endif
return true;
}
/// @brief Will try to get a float attribute value. /// @brief Will try to get a float attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The float value from the attribute. /// @param val [out] The float value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a float. /// @return true, if the node contains an attribute with the given name and if the value is a float.
static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) { static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_float();
return true;
}
/// @brief Will try to get a double attribute value. /// @brief Will try to get a double attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The double value from the attribute. /// @param val [out] The double value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a double. /// @return true, if the node contains an attribute with the given name and if the value is a double.
static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) { static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_double();
return true;
}
/// @brief Will try to get a std::string attribute value. /// @brief Will try to get a std::string attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The std::string value from the attribute. /// @param val [out] The std::string value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a std::string. /// @return true, if the node contains an attribute with the given name and if the value is a std::string.
static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) { static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_string();
return true;
}
/// @brief Will try to get a bool attribute value. /// @brief Will try to get a bool attribute value.
/// @param xmlNode [in] The node to search in. /// @param xmlNode [in] The node to search in.
/// @param name [in] The attribute name to look for. /// @param name [in] The attribute name to look for.
/// @param val [out] The bool value from the attribute. /// @param val [out] The bool value from the attribute.
/// @return true, if the node contains an attribute with the given name and if the value is a bool. /// @return true, if the node contains an attribute with the given name and if the value is a bool.
static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) { static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val);
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_bool();
return true;
}
/// @brief Will try to get the value of the node as a string. /// @brief Will try to get the value of the node as a string.
/// @param node [in] The node to search in. /// @param node [in] The node to search in.
/// @param text [out] The value as a text. /// @param text [out] The value as a text.
/// @return true, if the value can be read out. /// @return true, if the value can be read out.
static inline bool getValueAsString(XmlNode &node, std::string &text) { static inline bool getValueAsString(XmlNode &node, std::string &text);
text = std::string();
if (node.empty()) {
return false;
}
text = node.text().as_string();
return true;
}
/// @brief Will try to get the value of the node as a float. /// @brief Will try to get the value of the node as a float.
/// @param node [in] The node to search in. /// @param node [in] The node to search in.
/// @param text [out] The value as a float. /// @param text [out] The value as a float.
/// @return true, if the value can be read out. /// @return true, if the value can be read out.
static inline bool getValueAsFloat(XmlNode &node, ai_real &v) { static inline bool getValueAsFloat(XmlNode &node, ai_real &v);
if (node.empty()) {
return false;
}
v = node.text().as_float();
return true;
}
/// @brief Will try to get the value of the node as an integer. /// @brief Will try to get the value of the node as an integer.
/// @param node [in] The node to search in. /// @param node [in] The node to search in.
/// @param text [out] The value as a int. /// @param text [out] The value as a int.
/// @return true, if the value can be read out. /// @return true, if the value can be read out.
static inline bool getValueAsInt(XmlNode &node, int &v) { static inline bool getValueAsInt(XmlNode &node, int &v);
if (node.empty()) {
return false;
}
v = node.text().as_int();
return true;
}
/// @brief Will try to get the value of the node as an bool. /// @brief Will try to get the value of the node as an bool.
/// @param node [in] The node to search in. /// @param node [in] The node to search in.
/// @param text [out] The value as a bool. /// @param text [out] The value as a bool.
/// @return true, if the value can be read out. /// @return true, if the value can be read out.
static inline bool getValueAsBool(XmlNode& node, bool& v) static inline bool getValueAsBool(XmlNode &node, bool &v);
{
if (node.empty()) {
return false;
}
v = node.text().as_bool();
return true;
}
private: private:
pugi::xml_document *mDoc; pugi::xml_document *mDoc;
@ -395,6 +229,254 @@ private:
std::vector<char> mData; std::vector<char> mData;
}; };
template <class TNodeType>
inline TXmlParser<TNodeType>::TXmlParser() :
mDoc(nullptr),
mData() {
// empty
}
template <class TNodeType>
inline TXmlParser<TNodeType>::~TXmlParser() {
clear();
}
template <class TNodeType>
inline void TXmlParser<TNodeType>::clear() {
if (mData.empty()) {
if (mDoc) {
delete mDoc;
}
mDoc = nullptr;
return;
}
mData.clear();
delete mDoc;
mDoc = nullptr;
}
template <class TNodeType>
inline TNodeType *TXmlParser<TNodeType>::findNode(const std::string &name) {
if (name.empty()) {
return nullptr;
}
if (nullptr == mDoc) {
return nullptr;
}
find_node_by_name_predicate predicate(name);
mCurrent = mDoc->find_node(predicate);
if (mCurrent.empty()) {
return nullptr;
}
return &mCurrent;
}
template <class TNodeType>
bool TXmlParser<TNodeType>::hasNode(const std::string &name) {
return nullptr != findNode(name);
}
template <class TNodeType>
bool TXmlParser<TNodeType>::parse(IOStream *stream) {
if (hasRoot()) {
clear();
}
if (nullptr == stream) {
ASSIMP_LOG_DEBUG("Stream is nullptr.");
return false;
}
const size_t len = stream->FileSize();
mData.resize(len + 1);
memset(&mData[0], '\0', len + 1);
stream->Read(&mData[0], 1, len);
mDoc = new pugi::xml_document();
pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full);
if (parse_result.status == pugi::status_ok) {
return true;
}
ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
return false;
}
template <class TNodeType>
bool TXmlParser<TNodeType>::hasRoot() const {
return nullptr != mDoc;
}
template <class TNodeType>
pugi::xml_document *TXmlParser<TNodeType>::getDocument() const {
return mDoc;
}
template <class TNodeType>
const TNodeType TXmlParser<TNodeType>::getRootNode() const {
static pugi::xml_node none;
if (nullptr == mDoc) {
return none;
}
return mDoc->root();
}
template <class TNodeType>
TNodeType TXmlParser<TNodeType>::getRootNode() {
static pugi::xml_node none;
if (nullptr == mDoc) {
return none;
}
return mDoc->root();
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::hasNode(XmlNode &node, const char *name) {
pugi::xml_node child = node.find_child(find_node_by_name_predicate(name));
return !child.empty();
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::hasAttribute(XmlNode &xmlNode, const char *name) {
pugi::xml_attribute attr = xmlNode.attribute(name);
return !attr.empty();
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_uint();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getIntAttribute(XmlNode &xmlNode, const char *name, int &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_int();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
#ifdef ASSIMP_DOUBLE_PRECISION
val = attr.as_double();
#else
val = attr.as_float();
#endif
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_float();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_double();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_string();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) {
pugi::xml_attribute attr = xmlNode.attribute(name);
if (attr.empty()) {
return false;
}
val = attr.as_bool();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &text) {
text = std::string();
if (node.empty()) {
return false;
}
text = node.text().as_string();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getValueAsFloat(XmlNode &node, ai_real &v) {
if (node.empty()) {
return false;
}
v = node.text().as_float();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getValueAsInt(XmlNode &node, int &v) {
if (node.empty()) {
return false;
}
v = node.text().as_int();
return true;
}
template <class TNodeType>
inline bool TXmlParser<TNodeType>::getValueAsBool(XmlNode &node, bool &v) {
if (node.empty()) {
return false;
}
v = node.text().as_bool();
return true;
}
using XmlParser = TXmlParser<pugi::xml_node>; using XmlParser = TXmlParser<pugi::xml_node>;
/// @brief This class declares an iterator to loop through all children of the root node. /// @brief This class declares an iterator to loop through all children of the root node.

View File

@ -691,6 +691,15 @@ enum aiComponent
#define AI_CONFIG_FBX_CONVERT_TO_M \ #define AI_CONFIG_FBX_CONVERT_TO_M \
"AI_CONFIG_FBX_CONVERT_TO_M" "AI_CONFIG_FBX_CONVERT_TO_M"
// ---------------------------------------------------------------------------
/** @brief Will enable the skeleton structo to store bone data.
*
* This will decouple the bone coupling to the mesh. This feature is
* experimental.
*/
#define AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER \
"AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Set the vertex animation keyframe to be imported /** @brief Set the vertex animation keyframe to be imported
* *

View File

@ -120,7 +120,7 @@ extern "C" {
* primitive are actually present in a mesh. The #aiProcess_SortByPType flag * primitive are actually present in a mesh. The #aiProcess_SortByPType flag
* executes a special post-processing algorithm which splits meshes with * executes a special post-processing algorithm which splits meshes with
* *different* primitive types mixed up (e.g. lines and triangles) in several * *different* primitive types mixed up (e.g. lines and triangles) in several
* 'clean' submeshes. Furthermore there is a configuration option ( * 'clean' sub-meshes. Furthermore there is a configuration option (
* #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove * #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove
* specific kinds of primitives from the imported scene, completely and forever. * specific kinds of primitives from the imported scene, completely and forever.
* In many cases you'll probably want to set this setting to * In many cases you'll probably want to set this setting to
@ -269,12 +269,12 @@ struct aiBone {
unsigned int mNumWeights; unsigned int mNumWeights;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
// The bone armature node - used for skeleton conversion /// The bone armature node - used for skeleton conversion
// you must enable aiProcess_PopulateArmatureData to populate this /// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mArmature; C_STRUCT aiNode *mArmature;
// The bone node in the scene - used for skeleton conversion /// The bone node in the scene - used for skeleton conversion
// you must enable aiProcess_PopulateArmatureData to populate this /// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mNode; C_STRUCT aiNode *mNode;
#endif #endif
@ -296,7 +296,7 @@ struct aiBone {
#ifdef __cplusplus #ifdef __cplusplus
//! Default constructor /// @brief Default constructor
aiBone() AI_NO_EXCEPT aiBone() AI_NO_EXCEPT
: mName(), : mName(),
mNumWeights(0), mNumWeights(0),
@ -309,7 +309,7 @@ struct aiBone {
// empty // empty
} }
//! Copy constructor /// @brief Copy constructor
aiBone(const aiBone &other) : aiBone(const aiBone &other) :
mName(other.mName), mName(other.mName),
mNumWeights(other.mNumWeights), mNumWeights(other.mNumWeights),
@ -319,14 +319,27 @@ struct aiBone {
#endif #endif
mWeights(nullptr), mWeights(nullptr),
mOffsetMatrix(other.mOffsetMatrix) { mOffsetMatrix(other.mOffsetMatrix) {
if (other.mWeights && other.mNumWeights) { copyVertexWeights(other);
mWeights = new aiVertexWeight[mNumWeights]; }
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
void copyVertexWeights( const aiBone &other ) {
if (other.mWeights == nullptr || other.mNumWeights == 0) {
mWeights = nullptr;
mNumWeights = 0;
return;
} }
mNumWeights = other.mNumWeights;
if (mWeights) {
delete[] mWeights;
}
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
} }
//! Assignment operator //! Assignment operator
aiBone &operator=(const aiBone &other) { aiBone &operator = (const aiBone &other) {
if (this == &other) { if (this == &other) {
return *this; return *this;
} }
@ -334,21 +347,13 @@ struct aiBone {
mName = other.mName; mName = other.mName;
mNumWeights = other.mNumWeights; mNumWeights = other.mNumWeights;
mOffsetMatrix = other.mOffsetMatrix; mOffsetMatrix = other.mOffsetMatrix;
copyVertexWeights(other);
if (other.mWeights && other.mNumWeights) {
if (mWeights) {
delete[] mWeights;
}
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
}
return *this; return *this;
} }
bool operator==(const aiBone &rhs) const { bool operator==(const aiBone &rhs) const {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights) { if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
return false; return false;
} }
@ -937,6 +942,100 @@ struct aiMesh {
#endif // __cplusplus #endif // __cplusplus
}; };
struct aiSkeletonBone {
/// The parent bone index, is -1 one if this bone represents the root bone.
int mParent;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
/// The bone armature node - used for skeleton conversion
/// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mArmature;
/// The bone node in the scene - used for skeleton conversion
/// you must enable aiProcess_PopulateArmatureData to populate this
C_STRUCT aiNode *mNode;
#endif
/// @brief The number of weights
unsigned int mNumnWeights;
/// The mesh index, which will get influenced by the weight.
C_STRUCT aiMesh *mMeshId;
/// The influence weights of this bone, by vertex index.
C_STRUCT aiVertexWeight *mWeights;
/** Matrix that transforms from bone space to mesh space in bind pose.
*
* This matrix describes the position of the mesh
* in the local space of this bone when the skeleton was bound.
* Thus it can be used directly to determine a desired vertex position,
* given the world-space transform of the bone when animated,
* and the position of the vertex in mesh space.
*
* It is sometimes called an inverse-bind matrix,
* or inverse bind pose matrix.
*/
C_STRUCT aiMatrix4x4 mOffsetMatrix;
/// Matrix that transforms the locale bone in bind pose.
C_STRUCT aiMatrix4x4 mLocalMatrix;
#ifdef __cplusplus
aiSkeletonBone() :
mParent(-1),
mArmature(nullptr),
mNode(nullptr),
mNumnWeights(0),
mMeshId(nullptr),
mWeights(nullptr),
mOffsetMatrix(),
mLocalMatrix() {
// empty
}
~aiSkeletonBone() {
delete[] mWeights;
mWeights = nullptr;
}
#endif // __cplusplus
};
/**
* @brief
*/
struct aiSkeleton {
/**
*
*/
C_STRUCT aiString mName;
/**
*
*/
unsigned int mNumBones;
/**
*
*/
C_STRUCT aiSkeletonBone **mBones;
#ifdef __cplusplus
/**
*
*/
aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) {
// empty
}
/**
*
*/
~aiSkeleton() {
delete[] mBones;
}
#endif // __cplusplus
};
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif //! extern "C" #endif //! extern "C"

View File

@ -79,8 +79,7 @@ extern "C" {
* the imported scene does consist of only a single root node without children. * the imported scene does consist of only a single root node without children.
*/ */
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct ASSIMP_API aiNode struct ASSIMP_API aiNode {
{
/** The name of the node. /** The name of the node.
* *
* The name might be empty (length of zero) but all nodes which * The name might be empty (length of zero) but all nodes which
@ -343,6 +342,16 @@ struct aiScene
*/ */
C_STRUCT aiString mName; C_STRUCT aiString mName;
/**
*
*/
unsigned int mNumSkeletons;
/**
*
*/
C_STRUCT aiSkeleton **mSkeletons;
#ifdef __cplusplus #ifdef __cplusplus
//! Default constructor - set everything to 0/nullptr //! Default constructor - set everything to 0/nullptr
@ -383,6 +392,10 @@ struct aiScene
return mAnimations != nullptr && mNumAnimations > 0; return mAnimations != nullptr && mNumAnimations > 0;
} }
bool hasSkeletons() const {
return mSkeletons != nullptr && mNumSkeletons > 0;
}
//! Returns a short filename from a full path //! Returns a short filename from a full path
static const char* GetShortFilename(const char* filename) { static const char* GetShortFilename(const char* filename) {
const char* lastSlash = strrchr(filename, '/'); const char* lastSlash = strrchr(filename, '/');

View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.80.40 commit date:2019-01-07, commit time:23:37, hash:91a155833e59</authoring_tool>
</contributor>
<created>2019-01-08T17:44:11</created>
<modified>2019-01-08T17:44:11</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_effects>
<effect id="Material-effect">
<profile_COMMON>
<technique sid="common">
<lambert>
<diffuse>
<color sid="diffuse">0.8 0.8 0.8 1</color>
</diffuse>
<specular>
<color sid="specular">0 0.5 0 1</color>
</specular>
</lambert>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_images/>
<library_materials>
<material id="Material-material" name="Material">
<instance_effect url="#Material-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Cube-mesh" name="Cube">
<mesh>
<source id="Cube-mesh-positions">
<float_array id="Cube-mesh-positions-array" count="24">1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1</float_array>
<technique_common>
<accessor source="#Cube-mesh-positions-array" count="8" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Cube-mesh-normals">
<float_array id="Cube-mesh-normals-array" count="18">0 0 1 0 -1 0 -1 0 0 0 0 -1 1 0 0 0 1 0</float_array>
<technique_common>
<accessor source="#Cube-mesh-normals-array" count="6" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Cube-mesh-map-0">
<float_array id="Cube-mesh-map-0-array" count="72">0.625 0 0.375 0.25 0.375 0 0.625 0.25 0.375 0.5 0.375 0.25 0.625 0.5 0.375 0.75 0.375 0.5 0.625 0.75 0.375 1 0.375 0.75 0.375 0.5 0.125 0.75 0.125 0.5 0.875 0.5 0.625 0.75 0.625 0.5 0.625 0 0.625 0.25 0.375 0.25 0.625 0.25 0.625 0.5 0.375 0.5 0.625 0.5 0.625 0.75 0.375 0.75 0.625 0.75 0.625 1 0.375 1 0.375 0.5 0.375 0.75 0.125 0.75 0.875 0.5 0.875 0.75 0.625 0.75</float_array>
<technique_common>
<accessor source="#Cube-mesh-map-0-array" count="36" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Cube-mesh-vertices">
<input semantic="POSITION" source="#Cube-mesh-positions"/>
</vertices>
<polylist material="Material-material" count="12">
<input semantic="VERTEX" source="#Cube-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Cube-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Cube-mesh-map-0" offset="2" set="1"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>4 0 0 2 0 1 0 0 2 2 1 3 7 1 4 3 1 5 6 2 6 5 2 7 7 2 8 1 3 9 7 3 10 5 3 11 0 4 12 3 4 13 1 4 14 4 5 15 1 5 16 5 5 17 4 0 18 6 0 19 2 0 20 2 1 21 6 1 22 7 1 23 6 2 24 4 2 25 5 2 26 1 3 27 3 3 28 7 3 29 0 4 30 2 4 31 3 4 32 4 5 33 0 5 34 1 5 35</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers>
<controller id="Armature_Cube-skin" name="Armature">
<skin source="#Cube-mesh">
<bind_shape_matrix>1 0 0 -1 0 1 0 1 0 0 1 1 0 0 0 1</bind_shape_matrix>
<source id="Armature_Cube-skin-joints">
<Name_array id="Armature_Cube-skin-joints-array" count="1">Bone</Name_array>
<technique_common>
<accessor source="#Armature_Cube-skin-joints-array" count="1" stride="1">
<param name="JOINT" type="name"/>
</accessor>
</technique_common>
</source>
<source id="Armature_Cube-skin-bind_poses">
<float_array id="Armature_Cube-skin-bind_poses-array" count="16">0.7886752 0.2113248 0.5773504 -0.5773504 -0.5773503 0.5773503 0.5773503 1.154701 -0.2113249 -0.7886752 0.5773503 -0.5773502 0 0 0 1</float_array>
<technique_common>
<accessor source="#Armature_Cube-skin-bind_poses-array" count="1" stride="16">
<param name="TRANSFORM" type="float4x4"/>
</accessor>
</technique_common>
</source>
<source id="Armature_Cube-skin-weights">
<float_array id="Armature_Cube-skin-weights-array" count="8">1 1 1 1 1 1 1 1</float_array>
<technique_common>
<accessor source="#Armature_Cube-skin-weights-array" count="8" stride="1">
<param name="WEIGHT" type="float"/>
</accessor>
</technique_common>
</source>
<joints>
<input semantic="JOINT" source="#Armature_Cube-skin-joints"/>
<input semantic="INV_BIND_MATRIX" source="#Armature_Cube-skin-bind_poses"/>
</joints>
<vertex_weights count="8">
<input semantic="JOINT" source="#Armature_Cube-skin-joints" offset="0"/>
<input semantic="WEIGHT" source="#Armature_Cube-skin-weights" offset="1"/>
<vcount>1 1 1 1 1 1 1 1 </vcount>
<v>0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7</v>
</vertex_weights>
</skin>
</controller>
</library_controllers>
<library_animations>
<animation id="action_container-Armature" name="Armature">
<animation id="Armature_ArmatureAction_transform" name="Armature">
<source id="Armature_ArmatureAction_transform-input">
<float_array id="Armature_ArmatureAction_transform-input-array" count="40">0.04166662 0.08333331 0.125 0.1666666 0.2083333 0.25 0.2916666 0.3333333 0.375 0.4166666 0.4583333 0.5 0.5416667 0.5833333 0.625 0.6666667 0.7083333 0.75 0.7916667 0.8333333 0.875 0.9166667 0.9583333 1 1.041667 1.083333 1.125 1.166667 1.208333 1.25 1.291667 1.333333 1.375 1.416667 1.458333 1.5 1.541667 1.583333 1.625 1.666667</float_array>
<technique_common>
<accessor source="#Armature_ArmatureAction_transform-input-array" count="40" stride="1">
<param name="TIME" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Armature_ArmatureAction_transform-output">
<float_array id="Armature_ArmatureAction_transform-output-array" count="640">1 0 0 1 0 1 0 -1 0 0 1 0 0 0 0 1 0.9999878 3.10816e-5 0.004935208 1 0 0.9999802 -0.006297799 -1 -0.004935306 0.006297722 0.999968 0 0 0 0 1 0.999819 4.61727e-4 0.01901668 1 0 0.9997054 -0.02427293 -1 -0.01902229 0.02426853 0.9995245 0 0 0 0 1 0.9991519 0.002163141 0.04111904 1 0 0.9986191 -0.05253414 -1 -0.04117589 0.05248959 0.9977722 0 0 0 0 1 0.9975264 0.006301912 0.07000974 1 0 0.9959731 -0.08965231 -1 -0.0702928 0.08943056 0.9935095 0 0 0 0 1 0.9944467 0.01411698 0.1042901 1 0 0.9909625 -0.1341392 -1 -0.1052413 0.1333943 0.9854594 0 0 0 0 1 0.9894527 0.02671701 0.1423712 1 0 0.9828442 -0.184438 -1 -0.1448563 0.1824927 0.9724778 0 0 0 0 1 0.9821799 0.04490547 0.1825 1 0 0.9710366 -0.2389307 -1 -0.1879434 0.234673 0.9537326 0 0 0 0 1 0.9724072 0.06904543 0.2228386 1 0 0.9551992 -0.2959637 -1 -0.2332902 0.2877972 0.9288425 0 0 0 0 1 0.9600915 0.09897761 0.261587 1 0 0.9352878 -0.3538882 -1 -0.2796861 0.339765 0.8979618 0 0 0 0 1 0.9453882 0.1340003 0.2971281 1 0 0.9115852 -0.4111113 -1 -0.3259466 0.3886598 0.8618018 0 0 0 0 1 0.9286572 0.1729132 0.328172 1 0 0.8847058 -0.4661497 -1 -0.3709391 0.4328933 0.8215885 0 0 0 0 1 0.9104556 0.2141147 0.3538722 1 0 0.8555763 -0.5176768 -1 -0.4136069 0.4713217 0.7789642 0 0 0 0 1 0.8915175 0.2557371 0.3738919 1 0 0.8253933 -0.5645581 -1 -0.4529863 0.5033134 0.7358525 0 0 0 0 1 0.8727233 0.2957927 0.388408 1 0 0.7955672 -0.6058654 -1 -0.4882152 0.5287529 0.6943099 0 0 0 0 1 0.8550603 0.332307 0.3980502 1 0 0.7676533 -0.6408653 -1 -0.5185286 0.5479785 0.6563899 0 0 0 0 1 0.8395769 0.3634188 0.4037789 1 0 0.7432778 -0.6689829 -1 -0.5432408 0.5616626 0.6240388 0 0 0 0 1 0.8273312 0.3874339 0.4067161 1 0 0.7240622 -0.6897347 -1 -0.5617144 0.5706391 0.5990393 0 0 0 0 1 0.8193359 0.4028329 0.4079393 1 0 0.7115462 -0.7026393 -1 -0.5733138 0.5756976 0.5829953 0 0 0 0 1 0.8164964 0.4082482 0.4082486 1 7.75722e-8 0.707107 -0.7071065 -1 -0.5773504 0.57735 0.5773503 0 0 0 0 1 0.8190646 0.4033515 0.4079717 1 7.78161e-8 0.7111219 -0.7030687 -1 -0.5737014 0.5758587 0.5824547 0 0 0 0 1 0.8263245 0.3893851 0.4068995 1 7.85059e-8 0.7224849 -0.6913868 -1 -0.5631944 0.5713098 0.5970069 0 0 0 0 1 0.8375081 0.3675125 0.4043696 1 7.95684e-8 0.7400277 -0.6725764 -1 -0.5464249 0.5632883 0.6197791 0 0 0 0 1 0.8517552 0.3390183 0.3994742 1 8.0922e-8 0.7624427 -0.6470557 -1 -0.5239399 0.5511332 0.6494145 0 0 0 0 1 0.8681612 0.3053284 0.3912425 1 8.24806e-8 0.7883466 -0.6152314 -1 -0.4962822 0.5341201 0.6844119 0 0 0 0 1 0.8858209 0.2680094 0.3788038 1 8.41584e-8 0.8163394 -0.5775725 -1 -0.4640273 0.5116258 0.7231305 0 0 0 0 1 0.9038687 0.2287352 0.3615268 1 8.58731e-8 0.8450637 -0.5346656 -1 -0.42781 0.4832675 0.7638266 0 0 0 0 1 0.9215156 0.1892192 0.339124 1 8.75496e-8 0.8732626 -0.4872499 -1 -0.3883413 0.4490085 0.8047251 0 0 0 0 1 0.9380813 0.1511175 0.3117163 1 8.91235e-8 0.899834 -0.4362323 -1 -0.3464153 0.4092214 0.8441175 0 0 0 0 1 0.9530206 0.1159168 0.2798482 1 9.05428e-8 0.9238796 -0.3826832 -1 -0.3029055 0.3647051 0.8804763 0 0 0 0 1 0.965943 0.08482374 0.2444564 1 9.17705e-8 0.9447417 -0.3278156 -1 -0.2587547 0.3166512 0.9125667 0 0 0 0 1 0.9766233 0.05867312 0.2067956 1 9.27852e-8 0.9620277 -0.2729518 -1 -0.2149581 0.2665711 0.9395387 0 0 0 0 1 0.9850019 0.03787052 0.1683363 1 9.35812e-8 0.975616 -0.2194843 -1 -0.1725436 0.2161924 0.9609836 0 0 0 0 1 0.991176 0.02237916 0.1306496 1 9.41678e-8 0.9856446 -0.1688333 -1 -0.1325524 0.1673435 0.9769473 0 0 0 0 1 0.9953793 0.01175384 0.09529842 1 9.45671e-8 0.9924796 -0.1224106 -1 -0.09602053 0.121845 0.9878936 0 0 0 0 1 0.997952 0.005218936 0.06375288 1 9.48115e-8 0.996666 -0.08159051 -1 -0.06396614 0.08142342 0.9946249 0 0 0 0 1 0.9993011 0.001782816 0.03733916 1 9.49397e-8 0.998862 -0.04769476 -1 -0.0373817 0.04766143 0.9981638 0 0 0 0 1 0.9998515 3.78837e-4 0.01722835 1 9.4992e-8 0.9997582 -0.02198936 -1 -0.01723252 0.0219861 0.9996098 0 0 0 0 1 0.99999 2.53135e-5 0.004462156 1 9.50052e-8 0.9999838 -0.00569412 -1 -0.004462227 0.005694063 0.9999738 0 0 0 0 1 1 0 0 2 0 1 0 -1 0 0 1 0 0 0 0 1</float_array>
<technique_common>
<accessor source="#Armature_ArmatureAction_transform-output-array" count="40" stride="16">
<param name="TRANSFORM" type="float4x4"/>
</accessor>
</technique_common>
</source>
<source id="Armature_ArmatureAction_transform-interpolation">
<Name_array id="Armature_ArmatureAction_transform-interpolation-array" count="40">LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR</Name_array>
<technique_common>
<accessor source="#Armature_ArmatureAction_transform-interpolation-array" count="40" stride="1">
<param name="INTERPOLATION" type="name"/>
</accessor>
</technique_common>
</source>
<sampler id="Armature_ArmatureAction_transform-sampler">
<input semantic="INPUT" source="#Armature_ArmatureAction_transform-input"/>
<input semantic="OUTPUT" source="#Armature_ArmatureAction_transform-output"/>
<input semantic="INTERPOLATION" source="#Armature_ArmatureAction_transform-interpolation"/>
</sampler>
<channel source="#Armature_ArmatureAction_transform-sampler" target="Armature_Bone/transform"/>
</animation>
</animation>
</library_animations>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Armature" name="Armature" type="NODE">
<matrix sid="transform">1 0 0 1 0 1 0 -1 0 0 1 0 0 0 0 1</matrix>
<node id="Armature_Bone" name="Bone" sid="Bone" type="JOINT">
<matrix sid="transform">0.7886751 -0.5773503 -0.211325 0 0.2113248 0.5773503 -0.7886751 0 0.5773503 0.5773503 0.5773502 0 0 0 0 1</matrix>
<extra>
<technique profile="blender">
<layer sid="layer" type="string">0</layer>
<roll sid="roll" type="float">-0.5235989</roll>
<tip_x sid="tip_x" type="float">-2</tip_x>
<tip_y sid="tip_y" type="float">2</tip_y>
<tip_z sid="tip_z" type="float">2</tip_z>
</technique>
</extra>
</node>
<node id="Cube" name="Cube" type="NODE">
<translate sid="location">0 0 0</translate>
<rotate sid="rotationZ">0 0 1 0</rotate>
<rotate sid="rotationY">0 1 0 0</rotate>
<rotate sid="rotationX">1 0 0 0</rotate>
<scale sid="scale">1 1 1</scale>
<instance_controller url="#Armature_Cube-skin">
<skeleton>#Armature_Bone</skeleton>
<bind_material>
<technique_common>
<instance_material symbol="Material-material" target="#Material-material">
<bind_vertex_input semantic="UVMap" input_semantic="TEXCOORD" input_set="0"/>
</instance_material>
</technique_common>
</bind_material>
</instance_controller>
</node>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>

Binary file not shown.

View File

@ -69,31 +69,44 @@ public:
virtual bool importerTest() final { virtual bool importerTest() final {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure); {
if (scene == nullptr) const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure);
return false; if (scene == nullptr)
return false;
// Expected number of items // Expected number of items
EXPECT_EQ(scene->mNumMeshes, 1u); EXPECT_EQ(scene->mNumMeshes, 1u);
EXPECT_EQ(scene->mNumMaterials, 1u); EXPECT_EQ(scene->mNumMaterials, 1u);
EXPECT_EQ(scene->mNumAnimations, 0u); EXPECT_EQ(scene->mNumAnimations, 0u);
EXPECT_EQ(scene->mNumTextures, 0u); EXPECT_EQ(scene->mNumTextures, 0u);
EXPECT_EQ(scene->mNumLights, 1u); EXPECT_EQ(scene->mNumLights, 1u);
EXPECT_EQ(scene->mNumCameras, 1u); EXPECT_EQ(scene->mNumCameras, 1u);
// Expected common metadata // Expected common metadata
aiString value; aiString value;
EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, value)) << "No importer format metadata"; EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, value)) << "No importer format metadata";
EXPECT_STREQ("Collada Importer", value.C_Str()); EXPECT_STREQ("Collada Importer", value.C_Str());
EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, value)) << "No format version metadata"; EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, value)) << "No format version metadata";
EXPECT_STREQ("1.4.1", value.C_Str()); EXPECT_STREQ("1.4.1", value.C_Str());
EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, value)) << "No generator metadata"; EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, value)) << "No generator metadata";
EXPECT_EQ(strncmp(value.C_Str(), "Maya 8.0", 8), 0) << "AI_METADATA_SOURCE_GENERATOR was: " << value.C_Str(); EXPECT_EQ(strncmp(value.C_Str(), "Maya 8.0", 8), 0) << "AI_METADATA_SOURCE_GENERATOR was: " << value.C_Str();
EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) << "No copyright metadata"; EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) << "No copyright metadata";
EXPECT_EQ(strncmp(value.C_Str(), "Copyright 2006", 14), 0) << "AI_METADATA_SOURCE_COPYRIGHT was: " << value.C_Str(); EXPECT_EQ(strncmp(value.C_Str(), "Copyright 2006", 14), 0) << "AI_METADATA_SOURCE_COPYRIGHT was: " << value.C_Str();
}
{
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/box_nested_animation.dae", aiProcess_ValidateDataStructure);
if (scene == nullptr)
return false;
// Expect only one animation with the correct name
EXPECT_EQ(scene->mNumAnimations, 1u);
EXPECT_EQ(std::string(scene->mAnimations[0]->mName.C_Str()), std::string("Armature"));
}
return true; return true;
} }

View File

@ -423,3 +423,10 @@ TEST_F(utFBXImporterExporter, importMaxPbrMaterialsSpecularGloss) {
ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS); ASSERT_EQ(mat->Get("$raw.3dsMax|main|emit_color", aiTextureType_NONE, 0, emitColor), aiReturn_SUCCESS);
EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1)); EXPECT_EQ(emitColor, aiColor4D(1, 0, 1, 1));
} }
TEST_F(utFBXImporterExporter, importSkeletonTest) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/animation_with_skeleton.fbx", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, scene);
ASSERT_TRUE(scene->mRootNode);
}

View File

@ -40,6 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "AbstractImportExportBase.h" #include "AbstractImportExportBase.h"
#include <assimp/scene.h>
#include "UnitTestPCH.h" #include "UnitTestPCH.h"
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
@ -51,11 +53,12 @@ public:
bool importerTest() override { bool importerTest() override {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OpenGEX/Example.ogex", 0); const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OpenGEX/Example.ogex", 0);
EXPECT_EQ(1u, scene->mNumMeshes);
return nullptr != scene; return nullptr != scene;
} }
}; };
TEST_F(utOpenGEXImportExport, importLWSFromFileTest) { TEST_F(utOpenGEXImportExport, importOpenGexFromFileTest) {
EXPECT_TRUE(importerTest()); EXPECT_TRUE(importerTest());
} }