update assimp lib

This commit is contained in:
marauder2k7 2024-12-09 20:22:47 +00:00
parent 03a348deb7
commit d3f8fee74e
1725 changed files with 196314 additions and 62009 deletions

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXUtil.h"
#include <assimp/defs.h>
#include <stdint.h>
#include <cstdint>
#include <assimp/Exceptional.h>
#include <assimp/ByteSwapper.h>
#include <assimp/DefaultLogger.hpp>
@ -139,6 +140,7 @@ size_t Offset(const char* begin, const char* cursor) {
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void TokenizeError(const std::string& message, const char* begin, const char* cursor) AI_WONT_RETURN_SUFFIX;
void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
TokenizeError(message, Offset(begin, cursor));
}
@ -341,8 +343,7 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input,
// ------------------------------------------------------------------------------------------------
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits)
{
bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
// the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@ -408,7 +409,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// XXX this is vulnerable to stack overflowing ..
while(Offset(input, cursor) < end_offset - sentinel_block_length) {
ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
}
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
@ -431,8 +432,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
// ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
{
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
@ -465,7 +465,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
try
{
while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
break;
}
}

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -55,6 +55,7 @@ const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 nul
'\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?)
static std::string NULL_RECORD_STRING(NumNullRecords, '\0');
const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -55,9 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/MathFunctions.h>
#include <assimp/StringComparison.h>
#include <assimp/scene.h>
#include <assimp/CreateAnimMesh.h>
#include <assimp/StringUtils.h>
#include <assimp/commonMetaData.h>
@ -78,6 +76,53 @@ using namespace Util;
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
static void correctRootTransform(const aiScene *scene) {
if (scene == nullptr) {
return;
}
if (scene->mMetaData == nullptr) {
return;
}
int32_t UpAxis = 1, UpAxisSign = 1, FrontAxis = 2, FrontAxisSign = 1, CoordAxis = 0, CoordAxisSign = 1;
double UnitScaleFactor = 1.0;
for (unsigned MetadataIndex = 0; MetadataIndex < scene->mMetaData->mNumProperties; ++MetadataIndex) {
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxis") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxis);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxisSign") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxisSign);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxis") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxis);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxisSign") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxisSign);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxis") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxis);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxisSign") == 0) {
scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxisSign);
}
if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UnitScaleFactor") == 0) {
scene->mMetaData->Get<double>(MetadataIndex, UnitScaleFactor);
}
}
aiVector3D upVec, forwardVec, rightVec;
upVec[UpAxis] = UpAxisSign * static_cast<float>(UnitScaleFactor);
forwardVec[FrontAxis] = FrontAxisSign * static_cast<float>(UnitScaleFactor);
rightVec[CoordAxis] = CoordAxisSign * (float)UnitScaleFactor;
aiMatrix4x4 mat(rightVec.x, rightVec.y, rightVec.z, 0.0f,
upVec.x, upVec.y, upVec.z, 0.0f,
forwardVec.x, forwardVec.y, forwardVec.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
scene->mRootNode->mTransformation *= mat;
}
FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) :
defaultMaterialIndex(),
mMeshes(),
@ -93,6 +138,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
mSceneOut(out),
doc(doc),
mRemoveEmptyBones(removeEmptyBones) {
// animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated.
@ -119,7 +166,7 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
if (mat) {
if (materials_converted.find(mat) == materials_converted.end()) {
ConvertMaterial(*mat, 0);
ConvertMaterial(*mat, nullptr);
}
}
}
@ -133,6 +180,10 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
// need not contain geometry (i.e. camera animations, raw armatures).
if (out->mNumMeshes == 0) {
out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} else {
// Apply the FBX axis metadata unless requested not to
if (!doc.Settings().ignoreUpDirection)
correctRootTransform(mSceneOut);
}
}
@ -196,7 +247,7 @@ struct FBXConverter::PotentialNode {
/// todo: get bone from stack
/// todo: make map of aiBone* to aiNode*
/// then update convert clusters to the new format
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform) {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
std::vector<PotentialNode> nodes;
@ -227,7 +278,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
if (nullptr != model) {
nodes_chain.clear();
post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent->mTransformation;
aiMatrix4x4 new_abs_transform = parent_transform;
std::string node_name = FixNodeName(model->Name());
// even though there is only a single input node, the design of
// assimp (or rather: the complicated transformation chain that
@ -261,6 +312,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
child->mParent = last_parent;
last_parent = child.mNode;
new_abs_transform *= child->mTransformation;
}
// attach geometry
@ -283,6 +336,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
postnode->mParent = last_parent;
last_parent = postnode.mNode;
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
@ -290,7 +345,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
}
// recursion call - child nodes
ConvertNodes(model->ID(), last_parent, root_node);
ConvertNodes(model->ID(), last_parent, root_node, new_abs_transform);
if (doc.Settings().readLights) {
ConvertLights(*model, node_name);
@ -305,18 +360,15 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
}
}
if (nodes.size()) {
parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
for (unsigned int i = 0; i < nodes.size(); ++i)
{
parent->mChildren[i] = nodes[i].mOwnership.release();
}
nodes.clear();
} else {
if (nodes.empty()) {
parent->mNumChildren = 0;
parent->mChildren = nullptr;
} else {
parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
for (unsigned int i = 0; i < nodes.size(); ++i) {
parent->mChildren[i] = nodes[i].mOwnership.release();
}
}
}
@ -424,16 +476,32 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
// NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
// All transformations to the camera will be handled by its node in the scenegraph.
out_camera->mPosition = aiVector3D(0.0f);
out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
// NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
// mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane();
// TODO: This is not a complete solution for how FBX cameras can be stored.
// TODO: Incorporate non-square pixel aspect ratio.
// TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
float fov_deg = cam.FieldOfView();
// If FOV not specified in file, compute using FilmWidth and FocalLength.
if (fov_deg == kFovUnknown) {
float film_width_inches = cam.FilmWidth();
float focal_length_mm = cam.FocalLength();
ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
} else {
// FBX fov is full-view degrees. We want half-view radians.
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
}
out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
out_camera->mClipPlaneNear = cam.NearPlane();
out_camera->mClipPlaneFar = cam.FarPlane();
}
@ -562,16 +630,17 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool is_id[3] = { true, true, true };
aiMatrix4x4 temp[3];
if (std::fabs(rotation.z) > angle_epsilon) {
aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]);
const auto rot = AI_DEG_TO_RAD(rotation);
if (std::fabs(rot.z) > angle_epsilon) {
aiMatrix4x4::RotationZ(rot.z, temp[2]);
is_id[2] = false;
}
if (std::fabs(rotation.y) > angle_epsilon) {
aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]);
if (std::fabs(rot.y) > angle_epsilon) {
aiMatrix4x4::RotationY(rot.y, temp[1]);
is_id[1] = false;
}
if (std::fabs(rotation.x) > angle_epsilon) {
aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]);
if (std::fabs(rot.x) > angle_epsilon) {
aiMatrix4x4::RotationX(rot.x, temp[0]);
is_id[0] = false;
}
@ -643,13 +712,12 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props();
const auto zero_epsilon = ai_epsilon;
const auto zero_epsilon = Math::getEpsilon<ai_real>();
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i);
if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
comp == TransformationComp_PreRotation || comp == TransformationComp_PostRotation) {
if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) {
continue;
}
@ -876,8 +944,12 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
data->Set(index++, prop.first, interpretedBool->Value());
} else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
data->Set(index++, prop.first, interpretedInt->Value());
} else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
data->Set(index++, prop.first, interpretedUInt->Value());
} else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
data->Set(index++, prop.first, interpretedUint64->Value());
} else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
data->Set(index++, prop.first, interpretedint64->Value());
} else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
data->Set(index++, prop.first, interpretedFloat->Value());
} else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
@ -1179,19 +1251,27 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
const auto &curNormals = shapeGeometry->GetNormals();
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh, true, !curNormals.empty());
const auto &curVertices = shapeGeometry->GetVertices();
const auto &curIndices = shapeGeometry->GetIndices();
//losing channel name if using shapeGeometry->Name()
animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name()));
// if blendShapeChannel Name is empty or doesn't have a ".", add geoMetryName;
auto aniName = FixAnimMeshName(blendShapeChannel->Name());
auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
if (aniName.empty()) {
aniName = geoMetryName;
}
else if (aniName.find('.') == aniName.npos) {
aniName += "." + geoMetryName;
}
animMesh->mName.Set(aniName);
for (size_t j = 0; j < curIndices.size(); j++) {
const unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j);
aiVector3D normal = curNormals.at(j);
aiVector3D normal = curNormals.empty() ? aiVector3D() : curNormals.at(j);
unsigned int count = 0;
const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count);
for (unsigned int k = 0; k < count; k++) {
@ -1409,18 +1489,17 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
std::vector<aiAnimMesh *> animMeshes;
for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
const std::vector<const ShapeGeometry *> &shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (size_t i = 0; i < shapeGeometries.size(); i++) {
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
const ShapeGeometry *shapeGeometry = shapeGeometries.at(i);
const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
const auto& curNormals = shapeGeometry->GetNormals();
aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh, true, !curNormals.empty());
const auto& curVertices = shapeGeometry->GetVertices();
const auto& curIndices = shapeGeometry->GetIndices();
animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
for (size_t j = 0; j < curIndices.size(); j++) {
unsigned int curIndex = curIndices.at(j);
aiVector3D vertex = curVertices.at(j);
aiVector3D normal = curNormals.at(j);
aiVector3D normal = curNormals.empty() ? aiVector3D() : curNormals.at(j);
unsigned int count = 0;
const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count);
for (unsigned int k = 0; k < count; k++) {
@ -1458,7 +1537,9 @@ static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *s
skeletonBone->mWeights = bone->mWeights;
skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
skeletonBone->mMeshId = mesh;
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
skeletonBone->mNode = bone->mNode;
#endif
skeletonBone->mParent = -1;
}
@ -1566,7 +1647,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
out->mBones = nullptr;
out->mNumBones = 0;
return;
}
}
out->mBones = new aiBone *[bones.size()]();
out->mNumBones = static_cast<unsigned int>(bones.size());
@ -1575,7 +1656,7 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const ai
void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
aiNode *) {
ai_assert(cluster != nullptr); // make sure cluster valid
@ -1592,16 +1673,16 @@ void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const
bone = new aiBone();
bone->mName = bone_name;
bone->mOffsetMatrix = cluster->Transform();
//bone->mOffsetMatrix = cluster->Transform();
// store local transform link for post processing
/*
bone->mOffsetMatrix = cluster->TransformLink();
bone->mOffsetMatrix.Inverse();
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
const aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
*/
//
// Now calculate the aiVertexWeights
//
@ -1784,7 +1865,7 @@ aiString FBXConverter::GetTexturePath(const Texture *tex) {
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
// This may occur on this case too, it has to be studied
path.data[0] = '*';
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
}
}
}
@ -2052,6 +2133,10 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_
TrySetTextureProperties(out_mat, _textures, "Maya|emissionColor", aiTextureType_EMISSION_COLOR, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|metalness", aiTextureType_METALNESS, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|diffuseRoughness", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|base", aiTextureType_MAYA_BASE, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|specular", aiTextureType_MAYA_SPECULAR, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|specularColor", aiTextureType_MAYA_SPECULAR_COLOR, mesh);
TrySetTextureProperties(out_mat, _textures, "Maya|specularRoughness", aiTextureType_MAYA_SPECULAR_ROUGHNESS, mesh);
// Maya stingray
TrySetTextureProperties(out_mat, _textures, "Maya|TEX_color_map", aiTextureType_BASE_COLOR, mesh);
@ -2364,7 +2449,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTa
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
path.data[0] = '*';
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
}
out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0);
@ -2730,7 +2815,7 @@ void FBXConverter::ProcessMorphAnimDatas(std::map<std::string, morphAnimData *>
auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo);
auto geoIndex = static_cast<unsigned int>(std::distance(model->GetGeometry().begin(), geoIt));
auto name = aiString(FixNodeName(model->Name() + "*"));
name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex);
name.length = 1 + ASSIMP_itoa10(name.data + name.length, AI_MAXLEN - 1, geoIndex);
morphAnimData *animData;
auto animIt = morphAnimDatas->find(name.C_Str());
if (animIt == morphAnimDatas->end()) {
@ -3197,7 +3282,6 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
aiVector3D defTranslate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f));
aiVector3D defRotation = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f));
aiVector3D defScale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f));
aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder);
aiVectorKey* outTranslations = new aiVectorKey[keyCount];
aiQuatKey* outRotations = new aiQuatKey[keyCount];
@ -3215,6 +3299,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
if (keyframeLists[TransformationComp_Rotation].size() > 0) {
InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
} else {
aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder);
for (size_t i = 0; i < keyCount; ++i) {
outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
outRotations[i].mValue = defQuat;
@ -3231,7 +3316,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
}
bool ok = false;
const auto zero_epsilon = ai_epsilon;
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -134,7 +134,7 @@ private:
// ------------------------------------------------------------------------------------------------
// collect and assign child nodes
void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node);
void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform = aiMatrix4x4());
// ------------------------------------------------------------------------------------------------
void ConvertLights(const Model& model, const std::string &orig_name );

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -84,7 +84,7 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
transform = ReadMatrix(Transform);
transformLink = ReadMatrix(TransformLink);
// it is actually possible that there be Deformer's with no weights
// it is actually possible that there are Deformer's with no weights
if (!!Indexes != !!Weights) {
DOMError("either Indexes or Weights are missing from Cluster",&element);
}
@ -154,8 +154,10 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc,
for (const Connection* con : conns) {
const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
if (bspc) {
blendShapeChannels.push_back(bspc);
continue;
auto pr = blendShapeChannels.insert(bspc);
if (!pr.second) {
FBXImporter::LogWarn("there is the same blendShapeChannel id ", bspc->ID());
}
}
}
}
@ -179,8 +181,10 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const
for (const Connection* con : conns) {
const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
if (sg) {
shapeGeometries.push_back(sg);
continue;
auto pr = shapeGeometries.insert(sg);
if (!pr.second) {
FBXImporter::LogWarn("there is the same shapeGeometrie id ", sg->ID());
}
}
}
}

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -78,7 +78,7 @@ const Object* LazyObject::Get(bool dieOnError) {
return nullptr;
}
if (object.get()) {
if (object) {
return object.get();
}
@ -199,6 +199,14 @@ const Object* LazyObject::Get(bool dieOnError) {
object.reset(new AnimationCurveNode(id,element,name,doc));
}
}
catch (std::bad_alloc&) {
// out-of-memory is unrecoverable and should always lead to a failure
flags &= ~BEING_CONSTRUCTED;
flags |= FAILED_TO_CONSTRUCT;
throw;
}
catch(std::exception& ex) {
flags &= ~BEING_CONSTRUCTED;
flags |= FAILED_TO_CONSTRUCT;
@ -214,7 +222,7 @@ const Object* LazyObject::Get(bool dieOnError) {
return nullptr;
}
if (!object.get()) {
if (!object) {
//DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
}
@ -235,7 +243,7 @@ FileGlobalSettings::FileGlobalSettings(const Document &doc, std::shared_ptr<cons
}
// ------------------------------------------------------------------------------------------------
Document::Document(const Parser& parser, const ImportSettings& settings) :
Document::Document(Parser& parser, const ImportSettings& settings) :
settings(settings), parser(parser) {
ASSIMP_LOG_DEBUG("Creating FBX Document");
@ -257,13 +265,17 @@ Document::Document(const Parser& parser, const ImportSettings& settings) :
}
// ------------------------------------------------------------------------------------------------
Document::~Document() {
for(ObjectMap::value_type& v : objects) {
delete v.second;
Document::~Document()
{
// The document does not own the memory for the following objects, but we need to call their d'tor
// so they can properly free memory like string members:
for (ObjectMap::value_type &v : objects) {
delete_LazyObject(v.second);
}
for(ConnectionMap::value_type& v : src_connections) {
delete v.second;
for (ConnectionMap::value_type &v : src_connections) {
delete_Connection(v.second);
}
// |dest_connections| contain the same Connection objects as the |src_connections|
}
@ -336,7 +348,7 @@ void Document::ReadGlobalSettings() {
DOMError("GlobalSettings dictionary contains no property table");
}
globals.reset(new FileGlobalSettings(*this, props));
globals.reset(new FileGlobalSettings(*this, std::move(props)));
}
// ------------------------------------------------------------------------------------------------
@ -348,9 +360,11 @@ void Document::ReadObjects() {
DOMError("no Objects dictionary found");
}
StackAllocator &allocator = parser.GetAllocator();
// add a dummy entry to represent the Model::RootNode object (id 0),
// which is only indirectly defined in the input file
objects[0] = new LazyObject(0L, *eobjects, *this);
objects[0] = new_LazyObject(0L, *eobjects, *this);
const Scope& sobjects = *eobjects->Compound();
for(const ElementMap::value_type& el : sobjects.Elements()) {
@ -373,11 +387,13 @@ void Document::ReadObjects() {
DOMError("encountered object with implicitly defined id 0",el.second);
}
if(objects.find(id) != objects.end()) {
const auto foundObject = objects.find(id);
if(foundObject != objects.end()) {
DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
delete_LazyObject(foundObject->second);
}
objects[id] = new LazyObject(id, *el.second, *this);
objects[id] = new_LazyObject(id, *el.second, *this);
// grab all animation stacks upfront since there is no listing of them
if(!strcmp(el.first.c_str(),"AnimationStack")) {
@ -444,8 +460,10 @@ void Document::ReadPropertyTemplates() {
}
// ------------------------------------------------------------------------------------------------
void Document::ReadConnections() {
const Scope& sc = parser.GetRootScope();
void Document::ReadConnections()
{
StackAllocator &allocator = parser.GetAllocator();
const Scope &sc = parser.GetRootScope();
// read property templates from "Definitions" section
const Element* const econns = sc["Connections"];
if(!econns || !econns->Compound()) {
@ -484,7 +502,7 @@ void Document::ReadConnections() {
}
// add new connection
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
src_connections.insert(ConnectionMap::value_type(src,c));
dest_connections.insert(ConnectionMap::value_type(dest,c));
}

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_DOCUMENT_H
#include <numeric>
#include <unordered_set>
#include <stdint.h>
#include <assimp/mesh.h>
#include "FBXProperties.h"
@ -54,9 +55,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define _AI_CONCAT(a,b) a ## b
#define AI_CONCAT(a,b) _AI_CONCAT(a,b)
namespace Assimp {
namespace FBX {
// Use an 'illegal' default FOV value to detect if the FBX camera has set the FOV.
static const float kFovUnknown = -1.0f;
class Parser;
class Object;
struct ImportSettings;
@ -80,6 +86,10 @@ class BlendShape;
class Skin;
class Cluster;
#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
#define delete_LazyObject(_p) (_p)->~LazyObject()
#define delete_Connection(_p) (_p)->~Connection()
/** Represents a delay-parsed FBX objects. Many objects in the scene
* are not needed by assimp, so it makes no sense to parse them
@ -168,7 +178,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
private:
@ -242,7 +252,7 @@ public:
fbx_simple_property(FilmAspectRatio, float, 1.0f)
fbx_simple_property(ApertureMode, int, 0)
fbx_simple_property(FieldOfView, float, 1.0f)
fbx_simple_property(FieldOfView, float, kFovUnknown)
fbx_simple_property(FocalLength, float, 1.0f)
};
@ -432,7 +442,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
/** Get material links */
@ -503,7 +513,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
// return a 4-tuple
@ -618,7 +628,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
const uint8_t* Content() const {
@ -632,7 +642,7 @@ public:
uint8_t* RelinquishContent() {
uint8_t* ptr = content;
content = 0;
content = nullptr;
return ptr;
}
@ -663,7 +673,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
const TextureMap& Textures() const {
@ -735,7 +745,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
@ -780,7 +790,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
/* the optional white list specifies a list of property names for which the caller
@ -808,7 +818,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
const AnimationLayerList& Layers() const {
@ -829,7 +839,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
private:
@ -855,14 +865,14 @@ public:
return fullWeights;
}
const std::vector<const ShapeGeometry*>& GetShapeGeometries() const {
const std::unordered_set<const ShapeGeometry*>& GetShapeGeometries() const {
return shapeGeometries;
}
private:
float percent;
WeightArray fullWeights;
std::vector<const ShapeGeometry*> shapeGeometries;
std::unordered_set<const ShapeGeometry*> shapeGeometries;
};
/** DOM class for BlendShape deformers */
@ -872,12 +882,12 @@ public:
virtual ~BlendShape();
const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const {
const std::unordered_set<const BlendShapeChannel*>& BlendShapeChannels() const {
return blendShapeChannels;
}
private:
std::vector<const BlendShapeChannel*> blendShapeChannels;
std::unordered_set<const BlendShapeChannel*> blendShapeChannels;
};
/** DOM class for skin deformer clusters (aka sub-deformers) */
@ -1018,7 +1028,7 @@ public:
const PropertyTable& Props() const {
ai_assert(props.get());
return *props.get();
return *props;
}
const Document& GetDocument() const {
@ -1072,7 +1082,7 @@ private:
/** DOM root for a FBX file */
class Document {
public:
Document(const Parser& parser, const ImportSettings& settings);
Document(Parser& parser, const ImportSettings& settings);
~Document();
@ -1097,7 +1107,7 @@ public:
const FileGlobalSettings& GlobalSettings() const {
ai_assert(globals.get());
return *globals.get();
return *globals;
}
const PropertyTemplateMap& Templates() const {
@ -1156,7 +1166,7 @@ private:
const ImportSettings& settings;
ObjectMap objects;
const Parser& parser;
Parser& parser;
PropertyTemplateMap templates;
ConnectionMap src_connections;

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -58,12 +58,11 @@ namespace Util {
/* DOM/Parse error reporting - does not return */
AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void DOMError(const std::string &message, const Element *element = nullptr) AI_WONT_RETURN_SUFFIX;
// does return
void DOMWarning(const std::string& message, const Token& token);
void DOMWarning(const std::string& message, const Element* element = NULL);
void DOMWarning(const std::string &message, const Element *element = nullptr);
// fetch a property table and the corresponding property template
std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -360,7 +360,7 @@ void FBX::Node::EndBinary(
bool has_children
) {
// if there were children, add a null record
if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); }
if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD_STRING); }
// now go back and write initial pos
this->end_pos = s.Tell();

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <string>
#include <utility>
#include <vector>
namespace Assimp {
@ -76,34 +77,30 @@ public: // constructors
/// The class constructor with the name.
Node(const std::string& n)
: name(n)
, properties()
, children()
, force_has_children( false ) {
// empty
}
// convenience template to construct with properties directly
template <typename... More>
Node(const std::string& n, const More... more)
Node(const std::string& n, More&&... more)
: name(n)
, properties()
, children()
, force_has_children(false) {
AddProperties(more...);
AddProperties(std::forward<More>(more)...);
}
public: // functions to add properties or children
// add a single property to the node
template <typename T>
void AddProperty(T value) {
properties.emplace_back(value);
void AddProperty(T&& value) {
properties.emplace_back(std::forward<T>(value));
}
// convenience function to add multiple properties at once
template <typename T, typename... More>
void AddProperties(T value, More... more) {
properties.emplace_back(value);
AddProperties(more...);
void AddProperties(T&& value, More&&... more) {
properties.emplace_back(std::forward<T>(value));
AddProperties(std::forward<More>(more)...);
}
void AddProperties() {}
@ -114,11 +111,11 @@ public: // functions to add properties or children
template <typename... More>
void AddChild(
const std::string& name,
More... more
More&&... more
) {
FBX::Node c(name);
c.AddProperties(more...);
children.push_back(c);
c.AddProperties(std::forward<More>(more)...);
children.push_back(std::move(c));
}
public: // support specifically for dealing with Properties70 nodes
@ -146,10 +143,10 @@ public: // support specifically for dealing with Properties70 nodes
const std::string& type,
const std::string& type2,
const std::string& flags,
More... more
More&&... more
) {
Node n("P");
n.AddProperties(name, type, type2, flags, more...);
n.AddProperties(name, type, type2, flags, std::forward<More>(more)...);
AddChild(n);
}
@ -214,7 +211,7 @@ public: // static member functions
bool binary, int indent
) {
FBX::FBXExportProperty p(value);
FBX::Node node(name, p);
FBX::Node node(name, std::move(p));
node.Dump(s, binary, indent);
}

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -58,23 +58,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/mesh.h>
// Header files, standard library.
#include <memory> // shared_ptr
#include <string>
#include <sstream> // stringstream
#include <array>
#include <ctime> // localtime, tm_*
#include <map>
#include <set>
#include <vector>
#include <array>
#include <unordered_set>
#include <memory> // shared_ptr
#include <numeric>
#include <set>
#include <sstream> // stringstream
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cmath>
// RESOURCES:
// https://code.blender.org/2013/08/fbx-binary-file-format-specification/
// https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian
using namespace Assimp;
using namespace Assimp::FBX;
@ -390,7 +390,7 @@ void FBXExporter::WriteHeaderExtension ()
raw[i] = uint8_t(GENERIC_FILEID[i]);
}
FBX::Node::WritePropertyNode(
"FileId", raw, outstream, binary, indent
"FileId", std::move(raw), outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"CreationTime", GENERIC_CTIME, outstream, binary, indent
@ -680,9 +680,9 @@ void FBXExporter::WriteDefinitions ()
pt = FBX::Node("PropertyTemplate", "FBXAnimLayer");
p = FBX::Node("Properties70");
p.AddP70("Weight", "Number", "", "A", double(100));
p.AddP70bool("Mute", 0);
p.AddP70bool("Solo", 0);
p.AddP70bool("Lock", 0);
p.AddP70bool("Mute", false);
p.AddP70bool("Solo", false);
p.AddP70bool("Lock", false);
p.AddP70color("Color", 0.8, 0.8, 0.8);
p.AddP70("BlendMode", "enum", "", "", int32_t(0));
p.AddP70("RotationAccumulationMode", "enum", "", "", int32_t(0));
@ -732,42 +732,42 @@ void FBXExporter::WriteDefinitions ()
p.AddP70vector("RotationPivot", 0.0, 0.0, 0.0);
p.AddP70vector("ScalingOffset", 0.0, 0.0, 0.0);
p.AddP70vector("ScalingPivot", 0.0, 0.0, 0.0);
p.AddP70bool("TranslationActive", 0);
p.AddP70bool("TranslationActive", false);
p.AddP70vector("TranslationMin", 0.0, 0.0, 0.0);
p.AddP70vector("TranslationMax", 0.0, 0.0, 0.0);
p.AddP70bool("TranslationMinX", 0);
p.AddP70bool("TranslationMinY", 0);
p.AddP70bool("TranslationMinZ", 0);
p.AddP70bool("TranslationMaxX", 0);
p.AddP70bool("TranslationMaxY", 0);
p.AddP70bool("TranslationMaxZ", 0);
p.AddP70bool("TranslationMinX", false);
p.AddP70bool("TranslationMinY", false);
p.AddP70bool("TranslationMinZ", false);
p.AddP70bool("TranslationMaxX", false);
p.AddP70bool("TranslationMaxY", false);
p.AddP70bool("TranslationMaxZ", false);
p.AddP70enum("RotationOrder", 0);
p.AddP70bool("RotationSpaceForLimitOnly", 0);
p.AddP70bool("RotationSpaceForLimitOnly", false);
p.AddP70double("RotationStiffnessX", 0.0);
p.AddP70double("RotationStiffnessY", 0.0);
p.AddP70double("RotationStiffnessZ", 0.0);
p.AddP70double("AxisLen", 10.0);
p.AddP70vector("PreRotation", 0.0, 0.0, 0.0);
p.AddP70vector("PostRotation", 0.0, 0.0, 0.0);
p.AddP70bool("RotationActive", 0);
p.AddP70bool("RotationActive", false);
p.AddP70vector("RotationMin", 0.0, 0.0, 0.0);
p.AddP70vector("RotationMax", 0.0, 0.0, 0.0);
p.AddP70bool("RotationMinX", 0);
p.AddP70bool("RotationMinY", 0);
p.AddP70bool("RotationMinZ", 0);
p.AddP70bool("RotationMaxX", 0);
p.AddP70bool("RotationMaxY", 0);
p.AddP70bool("RotationMaxZ", 0);
p.AddP70bool("RotationMinX", false);
p.AddP70bool("RotationMinY", false);
p.AddP70bool("RotationMinZ", false);
p.AddP70bool("RotationMaxX", false);
p.AddP70bool("RotationMaxY", false);
p.AddP70bool("RotationMaxZ", false);
p.AddP70enum("InheritType", 0);
p.AddP70bool("ScalingActive", 0);
p.AddP70bool("ScalingActive", false);
p.AddP70vector("ScalingMin", 0.0, 0.0, 0.0);
p.AddP70vector("ScalingMax", 1.0, 1.0, 1.0);
p.AddP70bool("ScalingMinX", 0);
p.AddP70bool("ScalingMinY", 0);
p.AddP70bool("ScalingMinZ", 0);
p.AddP70bool("ScalingMaxX", 0);
p.AddP70bool("ScalingMaxY", 0);
p.AddP70bool("ScalingMaxZ", 0);
p.AddP70bool("ScalingMinX", false);
p.AddP70bool("ScalingMinY", false);
p.AddP70bool("ScalingMinZ", false);
p.AddP70bool("ScalingMaxX", false);
p.AddP70bool("ScalingMaxY", false);
p.AddP70bool("ScalingMaxZ", false);
p.AddP70vector("GeometricTranslation", 0.0, 0.0, 0.0);
p.AddP70vector("GeometricRotation", 0.0, 0.0, 0.0);
p.AddP70vector("GeometricScaling", 1.0, 1.0, 1.0);
@ -788,11 +788,11 @@ void FBXExporter::WriteDefinitions ()
p.AddP70double("PreferedAngleZ", 0.0);
p.AddP70("LookAtProperty", "object", "", "");
p.AddP70("UpVectorProperty", "object", "", "");
p.AddP70bool("Show", 1);
p.AddP70bool("NegativePercentShapeSupport", 1);
p.AddP70bool("Show", true);
p.AddP70bool("NegativePercentShapeSupport", true);
p.AddP70int("DefaultAttributeIndex", -1);
p.AddP70bool("Freeze", 0);
p.AddP70bool("LODBox", 0);
p.AddP70bool("Freeze", false);
p.AddP70bool("LODBox", false);
p.AddP70(
"Lcl Translation", "Lcl Translation", "", "A",
double(0), double(0), double(0)
@ -839,9 +839,9 @@ void FBXExporter::WriteDefinitions ()
p.AddP70color("Color", 0, 0, 0);
p.AddP70vector("BBoxMin", 0, 0, 0);
p.AddP70vector("BBoxMax", 0, 0, 0);
p.AddP70bool("Primary Visibility", 1);
p.AddP70bool("Casts Shadows", 1);
p.AddP70bool("Receive Shadows", 1);
p.AddP70bool("Primary Visibility", true);
p.AddP70bool("Casts Shadows", true);
p.AddP70bool("Receive Shadows", true);
pt.AddChild(p);
n.AddChild(pt);
object_nodes.push_back(n);
@ -872,7 +872,7 @@ void FBXExporter::WriteDefinitions ()
} else {
p.AddP70string("ShadingModel", "Lambert");
}
p.AddP70bool("MultiLayer", 0);
p.AddP70bool("MultiLayer", false);
p.AddP70colorA("EmissiveColor", 0.0, 0.0, 0.0);
p.AddP70numberA("EmissiveFactor", 1.0);
p.AddP70colorA("AmbientColor", 0.2, 0.2, 0.2);
@ -909,7 +909,7 @@ void FBXExporter::WriteDefinitions ()
n.AddChild("Count", count);
pt = FBX::Node("PropertyTemplate", "FbxVideo");
p = FBX::Node("Properties70");
p.AddP70bool("ImageSequence", 0);
p.AddP70bool("ImageSequence", false);
p.AddP70int("ImageSequenceOffset", 0);
p.AddP70double("FrameRate", 0.0);
p.AddP70int("LastFrame", 0);
@ -921,8 +921,8 @@ void FBXExporter::WriteDefinitions ()
p.AddP70double("PlaySpeed", 0.0);
p.AddP70time("Offset", 0);
p.AddP70enum("InterlaceMode", 0);
p.AddP70bool("FreeRunning", 0);
p.AddP70bool("Loop", 0);
p.AddP70bool("FreeRunning", false);
p.AddP70bool("Loop", false);
p.AddP70enum("AccessMode", 0);
pt.AddChild(p);
n.AddChild(pt);
@ -943,8 +943,8 @@ void FBXExporter::WriteDefinitions ()
p.AddP70enum("CurrentMappingType", 0);
p.AddP70enum("WrapModeU", 0);
p.AddP70enum("WrapModeV", 0);
p.AddP70bool("UVSwap", 0);
p.AddP70bool("PremultiplyAlpha", 1);
p.AddP70bool("UVSwap", false);
p.AddP70bool("PremultiplyAlpha", true);
p.AddP70vectorA("Translation", 0.0, 0.0, 0.0);
p.AddP70vectorA("Rotation", 0.0, 0.0, 0.0);
p.AddP70vectorA("Scaling", 1.0, 1.0, 1.0);
@ -952,8 +952,8 @@ void FBXExporter::WriteDefinitions ()
p.AddP70vector("TextureScalingPivot", 0.0, 0.0, 0.0);
p.AddP70enum("CurrentTextureBlendMode", 1);
p.AddP70string("UVSet", "default");
p.AddP70bool("UseMaterial", 0);
p.AddP70bool("UseMipMap", 0);
p.AddP70bool("UseMaterial", false);
p.AddP70bool("UseMipMap", false);
pt.AddChild(p);
n.AddChild(pt);
object_nodes.push_back(n);
@ -1051,7 +1051,7 @@ aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node)
aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
{
std::vector<const aiNode*> node_chain;
while (node != scene->mRootNode) {
while (node != scene->mRootNode && node != nullptr) {
node_chain.push_back(node);
node = node->mParent;
}
@ -1062,14 +1062,14 @@ aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
return transform;
}
int64_t to_ktime(double ticks, const aiAnimation* anim) {
if (anim->mTicksPerSecond <= 0) {
inline int64_t to_ktime(double ticks, const aiAnimation* anim) {
if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) {
return static_cast<int64_t>(ticks) * FBX::SECOND;
}
return (static_cast<int64_t>(ticks) / static_cast<int64_t>(anim->mTicksPerSecond)) * FBX::SECOND;
return (static_cast<int64_t>(ticks / anim->mTicksPerSecond)) * FBX::SECOND;
}
int64_t to_ktime(double time) {
inline int64_t to_ktime(double time) {
return (static_cast<int64_t>(time * FBX::SECOND));
}
@ -1089,6 +1089,8 @@ void FBXExporter::WriteObjects ()
bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later
const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false);
// geometry (aiMesh)
mesh_uids.clear();
indent = 1;
@ -1215,10 +1217,8 @@ void FBXExporter::WriteObjects ()
}
// colors, if any
// TODO only one color channel currently
const int32_t colorChannelIndex = 0;
if (m->HasVertexColors(colorChannelIndex)) {
FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) {
FBX::Node vertexcolors("LayerElementColor", int32_t(ci));
vertexcolors.Begin(outstream, binary, indent);
vertexcolors.DumpProperties(outstream, binary, indent);
vertexcolors.EndProperties(outstream, binary, indent);
@ -1228,7 +1228,7 @@ void FBXExporter::WriteObjects ()
"Version", int32_t(101), outstream, binary, indent
);
char layerName[8];
sprintf(layerName, "COLOR_%d", colorChannelIndex);
snprintf(layerName, sizeof(layerName), "COLOR_%d", int32_t(ci));
FBX::Node::WritePropertyNode(
"Name", (const char*)layerName, outstream, binary, indent
);
@ -1245,7 +1245,7 @@ void FBXExporter::WriteObjects ()
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
const aiFace &f = m->mFaces[fi];
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
const aiColor4D &c = m->mColors[ci][f.mIndices[pvi]];
color_data.push_back(c.r);
color_data.push_back(c.g);
color_data.push_back(c.b);
@ -1352,11 +1352,14 @@ void FBXExporter::WriteObjects ()
le.AddChild("Type", "LayerElementNormal");
le.AddChild("TypedIndex", int32_t(0));
layer.AddChild(le);
// TODO only 1 color channel currently
le = FBX::Node("LayerElement");
le.AddChild("Type", "LayerElementColor");
le.AddChild("TypedIndex", int32_t(0));
layer.AddChild(le);
for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) {
le = FBX::Node("LayerElement");
le.AddChild("Type", "LayerElementColor");
le.AddChild("TypedIndex", int32_t(ci));
layer.AddChild(le);
}
le = FBX::Node("LayerElement");
le.AddChild("Type", "LayerElementMaterial");
le.AddChild("TypedIndex", int32_t(0));
@ -1390,7 +1393,7 @@ void FBXExporter::WriteObjects ()
aiMaterial* m = mScene->mMaterials[i];
// these are used to receive material data
float f; aiColor3D c;
ai_real f; aiColor3D c;
// start the node record
FBX::Node n("Material");
@ -1445,13 +1448,21 @@ void FBXExporter::WriteObjects ()
// "TransparentColor" / "TransparencyFactor"...
// thanks FBX, for your insightful interpretation of consistency
p.AddP70colorA("TransparentColor", c.r, c.g, c.b);
// TransparencyFactor defaults to 0.0, so set it to 1.0.
// note: Maya always sets this to 1.0,
// so we can't use it sensibly as "Opacity".
// In stead we rely on the legacy "Opacity" value, below.
// Blender also relies on "Opacity" not "TransparencyFactor",
// probably for a similar reason.
p.AddP70numberA("TransparencyFactor", 1.0);
if (!bTransparencyFactorReferencedToOpacity) {
// TransparencyFactor defaults to 0.0, so set it to 1.0.
// note: Maya always sets this to 1.0,
// so we can't use it sensibly as "Opacity".
// In stead we rely on the legacy "Opacity" value, below.
// Blender also relies on "Opacity" not "TransparencyFactor",
// probably for a similar reason.
p.AddP70numberA("TransparencyFactor", 1.0);
}
}
if (bTransparencyFactorReferencedToOpacity) {
if (m->Get(AI_MATKEY_OPACITY, f) == aiReturn_SUCCESS) {
p.AddP70numberA("TransparencyFactor", 1.0 - f);
}
}
if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) {
p.AddP70colorA("ReflectionColor", c.r, c.g, c.b);
@ -1707,7 +1718,7 @@ void FBXExporter::WriteObjects ()
p.AddP70vectorA("Scaling", trafo.mScaling[0], trafo.mScaling[1], 0.0);
p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify
//p.AddP70string("UVSet", ""); // TODO: how should this work?
p.AddP70bool("UseMaterial", 1);
p.AddP70bool("UseMaterial", true);
tnode.AddChild(p);
// can't easily determine which texture path will be correct,
// so just store what we have in every field.
@ -1749,7 +1760,7 @@ void FBXExporter::WriteObjects ()
int64_t blendshape_uid = generate_uid();
mesh_uids.push_back(blendshape_uid);
bsnode.AddProperty(blendshape_uid);
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Blendshape");
bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry");
bsnode.AddProperty("Shape");
bsnode.AddChild("Version", int32_t(100));
bsnode.Begin(outstream, binary, indent);
@ -1759,23 +1770,25 @@ void FBXExporter::WriteObjects ()
indent++;
if (pAnimMesh->HasPositions()) {
std::vector<int32_t>shape_indices;
std::vector<double>pPositionDiff;
std::vector<double>pNormalDiff;
std::vector<float>pPositionDiff;
std::vector<float>pNormalDiff;
for (unsigned int vt = 0; vt < vertex_indices.size(); ++vt) {
aiVector3D pDiff = (pAnimMesh->mVertices[vertex_indices[vt]] - m->mVertices[vertex_indices[vt]]);
if(pDiff.Length()>1e-8){
shape_indices.push_back(vertex_indices[vt]);
pPositionDiff.push_back(pDiff[0]);
pPositionDiff.push_back(pDiff[1]);
pPositionDiff.push_back(pDiff[2]);
shape_indices.push_back(vertex_indices[vt]);
pPositionDiff.push_back(pDiff[0]);
pPositionDiff.push_back(pDiff[1]);
pPositionDiff.push_back(pDiff[2]);
if (pAnimMesh->HasNormals()) {
aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]);
pNormalDiff.push_back(nDiff[0]);
pNormalDiff.push_back(nDiff[1]);
pNormalDiff.push_back(nDiff[2]);
}
if (pAnimMesh->HasNormals()) {
aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]);
pNormalDiff.push_back(nDiff[0]);
pNormalDiff.push_back(nDiff[1]);
pNormalDiff.push_back(nDiff[2]);
} else {
pNormalDiff.push_back(0.0);
pNormalDiff.push_back(0.0);
pNormalDiff.push_back(0.0);
}
}
@ -1808,7 +1821,7 @@ void FBXExporter::WriteObjects ()
p.AddP70numberA("DeformPercent", 0.0);
sdnode.AddChild(p);
// TODO: Normally just one weight per channel, adding stub for later development
std::vector<float>fFullWeights;
std::vector<double>fFullWeights;
fFullWeights.push_back(100.);
sdnode.AddChild("FullWeights", fFullWeights);
sdnode.Dump(outstream, binary, indent);
@ -1858,33 +1871,26 @@ void FBXExporter::WriteObjects ()
// one sticky point is that the number of vertices may not match,
// because assimp splits vertices by normal, uv, etc.
// functor for aiNode sorting
struct SortNodeByName
{
bool operator()(const aiNode *lhs, const aiNode *rhs) const
{
return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
}
};
// first we should mark the skeleton for each mesh.
// the skeleton must include not only the aiBones,
// but also all their parent nodes.
// anything that affects the position of any bone node must be included.
// Use SorNodeByName to make sure the exported result will be the same across all systems
// Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent
std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
// note that we want to preserve input order as much as possible here.
// previously, sorting by name lead to consistent output across systems, but was not
// suitable for downstream consumption by some applications.
std::vector<std::vector<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
// at the same time we can build a list of all the skeleton nodes,
// which will be used later to mark them as type "limbNode".
std::unordered_set<const aiNode*> limbnodes;
//actual bone nodes in fbx, without parenting-up
std::unordered_set<std::string> setAllBoneNamesInScene;
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
{
std::vector<std::string> allBoneNames;
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) {
aiMesh* pMesh = mScene->mMeshes[m];
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
allBoneNames.push_back(pMesh->mBones[b]->mName.data);
}
aiMatrix4x4 mxTransIdentity;
@ -1892,7 +1898,7 @@ void FBXExporter::WriteObjects ()
std::map<std::string,aiNode*> node_by_bone;
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
const aiMesh* m = mScene->mMeshes[mi];
std::set<const aiNode*, SortNodeByName> skeleton;
std::vector<const aiNode*> skeleton;
for (size_t bi =0; bi < m->mNumBones; ++bi) {
const aiBone* b = m->mBones[bi];
const std::string name(b->mName.C_Str());
@ -1911,7 +1917,7 @@ void FBXExporter::WriteObjects ()
node_by_bone[name] = n;
limbnodes.insert(n);
}
skeleton.insert(n);
skeleton.push_back(n);
// mark all parent nodes as skeleton as well,
// up until we find the root node,
// or else the node containing the mesh,
@ -1922,7 +1928,7 @@ void FBXExporter::WriteObjects ()
parent = parent->mParent
) {
// if we've already done this node we can skip it all
if (skeleton.count(parent)) {
if (std::find(skeleton.begin(), skeleton.end(), parent) != skeleton.end()) {
break;
}
// ignore fbx transform nodes as these will be collapsed later
@ -1932,7 +1938,7 @@ void FBXExporter::WriteObjects ()
continue;
}
//not a bone in scene && no effect in transform
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
if (std::find(allBoneNames.begin(), allBoneNames.end(), node_name) == allBoneNames.end()
&& parent->mTransformation == mxTransIdentity) {
continue;
}
@ -2017,7 +2023,7 @@ void FBXExporter::WriteObjects ()
aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
// now make a subdeformer for each bone in the skeleton
const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi];
const auto & skeleton= skeleton_by_mesh[mi];
for (const aiNode* bone_node : skeleton) {
// if there's a bone for this node, find it
const aiBone* b = nullptr;
@ -2414,7 +2420,7 @@ void FBXExporter::WriteObjects ()
// position/translation
for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) {
const aiVectorKey& k = na->mPositionKeys[ki];
times.push_back(to_ktime(k.mTime));
times.push_back(to_ktime(k.mTime, anim));
xval.push_back(k.mValue.x);
yval.push_back(k.mValue.y);
zval.push_back(k.mValue.z);
@ -2428,12 +2434,12 @@ void FBXExporter::WriteObjects ()
times.clear(); xval.clear(); yval.clear(); zval.clear();
for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) {
const aiQuatKey& k = na->mRotationKeys[ki];
times.push_back(to_ktime(k.mTime));
times.push_back(to_ktime(k.mTime, anim));
// TODO: aiQuaternion method to convert to Euler...
aiMatrix4x4 m(k.mValue.GetMatrix());
aiVector3D qs, qr, qt;
m.Decompose(qs, qr, qt);
qr *= DEG;
qr = AI_RAD_TO_DEG(qr);
xval.push_back(qr.x);
yval.push_back(qr.y);
zval.push_back(qr.z);
@ -2446,7 +2452,7 @@ void FBXExporter::WriteObjects ()
times.clear(); xval.clear(); yval.clear(); zval.clear();
for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) {
const aiVectorKey& k = na->mScalingKeys[ki];
times.push_back(to_ktime(k.mTime));
times.push_back(to_ktime(k.mTime, anim));
xval.push_back(k.mValue.x);
yval.push_back(k.mValue.y);
zval.push_back(k.mValue.z);
@ -2483,6 +2489,57 @@ const std::map<std::string,std::pair<std::string,char>> transform_types = {
{"GeometricScalingInverse", {"GeometricScalingInverse", 'i'}}
};
//add metadata to fbx property
void add_meta(FBX::Node& fbx_node, const aiNode* node){
if(node->mMetaData == nullptr) return;
aiMetadata* meta = node->mMetaData;
for (unsigned int i = 0; i < meta->mNumProperties; ++i) {
aiString key = meta->mKeys[i];
aiMetadataEntry* entry = &meta->mValues[i];
switch (entry->mType) {
case AI_BOOL:{
bool val = *static_cast<bool *>(entry->mData);
fbx_node.AddP70bool(key.C_Str(), val);
break;
}
case AI_INT32:{
int32_t val = *static_cast<int32_t *>(entry->mData);
fbx_node.AddP70int(key.C_Str(), val);
break;
}
case AI_UINT64:{
//use string to add uint64
uint64_t val = *static_cast<uint64_t *>(entry->mData);
fbx_node.AddP70string(key.C_Str(), std::to_string(val).c_str());
break;
}
case AI_FLOAT:{
float val = *static_cast<float *>(entry->mData);
fbx_node.AddP70double(key.C_Str(), val);
break;
}
case AI_DOUBLE:{
double val = *static_cast<double *>(entry->mData);
fbx_node.AddP70double(key.C_Str(), val);
break;
}
case AI_AISTRING:{
aiString val = *static_cast<aiString *>(entry->mData);
fbx_node.AddP70string(key.C_Str(), val.C_Str());
break;
}
case AI_AIMETADATA: {
//ignore
break;
}
default:
break;
}
}
}
// write a single model node to the stream
void FBXExporter::WriteModelNode(
StreamWriterLE& outstream,
@ -2497,10 +2554,10 @@ void FBXExporter::WriteModelNode(
const aiVector3D one = {1, 1, 1};
FBX::Node m("Model");
std::string name = node->mName.C_Str() + FBX::SEPARATOR + "Model";
m.AddProperties(node_uid, name, type);
m.AddProperties(node_uid, std::move(name), type);
m.AddChild("Version", int32_t(232));
FBX::Node p("Properties70");
p.AddP70bool("RotationActive", 1);
p.AddP70bool("RotationActive", true);
p.AddP70int("DefaultAttributeIndex", 0);
p.AddP70enum("InheritType", inherit_type);
if (transform_chain.empty()) {
@ -2514,9 +2571,10 @@ void FBXExporter::WriteModelNode(
);
}
if (r != zero) {
r = AI_RAD_TO_DEG(r);
p.AddP70(
"Lcl Rotation", "Lcl Rotation", "", "A",
double(DEG*r.x), double(DEG*r.y), double(DEG*r.z)
double(r.x), double(r.y), double(r.z)
);
}
if (s != one) {
@ -2549,6 +2607,7 @@ void FBXExporter::WriteModelNode(
}
}
}
add_meta(p, node);
m.AddChild(p);
// not sure what these are for,
@ -2600,8 +2659,7 @@ void FBXExporter::WriteModelNodes(
transform_chain.emplace_back(elem->first, t);
break;
case 'r': // rotation
r *= float(DEG);
transform_chain.emplace_back(elem->first, r);
transform_chain.emplace_back(elem->first, AI_RAD_TO_DEG(r));
break;
case 's': // scale
transform_chain.emplace_back(elem->first, s);

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -156,6 +156,9 @@ struct ImportSettings {
/** Set to true to perform a conversion from cm to meter after the import
*/
bool convertToMeters;
// Set to true to ignore the axis configuration in the file
bool ignoreUpDirection = false;
};
} // namespace FBX

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -62,8 +62,7 @@ namespace Assimp {
template <>
const char *LogFunctions<FBXImporter>::Prefix() {
static auto prefix = "FBX: ";
return prefix;
return "FBX: ";
}
} // namespace Assimp
@ -73,33 +72,25 @@ using namespace Assimp::Formatter;
using namespace Assimp::FBX;
namespace {
static const aiImporterDesc desc = {
"Autodesk FBX Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"fbx"
};
}
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer
FBXImporter::FBXImporter() :
mSettings() {
// empty
static constexpr aiImporterDesc desc = {
"Autodesk FBX Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"fbx"
};
}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
static const char *tokens[] = { "fbx" };
static const char *tokens[] = { " \n\r\n " };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
}
@ -126,6 +117,7 @@ void FBXImporter::SetupProperties(const Importer *pImp) {
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
mSettings.ignoreUpDirection = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION, false);
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
}
@ -156,19 +148,19 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// broad-phase tokenized pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings)
TokenList tokens;
try {
Assimp::StackAllocator tempAllocator;
try {
bool is_binary = false;
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
is_binary = true;
TokenizeBinary(tokens, begin, contents.size());
TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
} else {
Tokenize(tokens, begin);
Tokenize(tokens, begin, tempAllocator);
}
// use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure
Parser parser(tokens, is_binary);
Parser parser(tokens, tempAllocator, is_binary);
// take the raw parse-tree and convert it to a FBX DOM
Document doc(parser, mSettings);
@ -187,10 +179,12 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
// assimp universal format (M)
SetFileScale(size_relative_to_cm * 0.01f);
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
} catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
throw;
// This collection does not own the memory for the tokens, but we need to call their d'tor
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
} catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
throw;
}
}

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -70,7 +70,7 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
public:
/// @brief The class constructor.
FBXImporter();
FBXImporter() = default;
/// @brief The class destructor, default implementation.
~FBXImporter() override = default;

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -138,20 +138,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
// ------------------------------------------------------------------------------------------------
Material::~Material() = default;
aiVector2D uvTrans;
aiVector2D uvScaling;
ai_real uvRotation;
std::string type;
std::string relativeFileName;
std::string fileName;
std::string alphaSource;
std::shared_ptr<const PropertyTable> props;
unsigned int crop[4]{};
const Video* media;
// ------------------------------------------------------------------------------------------------
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
Object(id,element,name),
@ -292,10 +278,10 @@ void LayeredTexture::fillTexture(const Document& doc) {
}
// ------------------------------------------------------------------------------------------------
Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
Object(id,element,name),
Video::Video(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
Object(id, element, name),
contentLength(0),
content(0) {
content(nullptr) {
const Scope& sc = GetRequiredScope(element);
const Element* const Type = sc["Type"];
@ -380,9 +366,10 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
}
Video::~Video() {
delete[] content;
if (contentLength > 0) {
delete[] content;
}
}
} //!FBX

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -69,13 +69,16 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
}
const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
if (bsp) {
blendShapes.push_back(bsp);
auto pr = blendShapes.insert(bsp);
if (!pr.second) {
FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
}
}
}
}
// ------------------------------------------------------------------------------------------------
const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
const std::unordered_set<const BlendShape*>& Geometry::GetBlendShapes() const {
return blendShapes;
}
@ -415,9 +418,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
{
bool isDirect = ReferenceInformationType == "Direct";
bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
const bool hasDataElement = HasElement(source, dataElementName);
const bool hasIndexDataElement = HasElement(source, indexDataElementName);
// fall-back to direct data if there is no index data element
if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
if (isIndexToDirect && !hasIndexDataElement) {
isDirect = true;
isIndexToDirect = false;
}
@ -426,7 +431,8 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
// deal with this more elegantly and with less redundancy, but right
// now it seems unavoidable.
if (MappingInformationType == "ByVertice" && isDirect) {
if (!HasElement(source, dataElementName)) {
if (!hasDataElement) {
FBXImporter::LogWarn("missing data element: ", dataElementName);
return;
}
std::vector<T> tempData;
@ -448,14 +454,22 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
}
else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
if (!hasDataElement || !hasIndexDataElement) {
if (!hasDataElement)
FBXImporter::LogWarn("missing data element: ", dataElementName);
if (!hasIndexDataElement)
FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
return;
}
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
if (uvIndices.size() != vertex_count) {
if (uvIndices.size() != mapping_offsets.size()) {
FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
uvIndices.size(), ", expected ", vertex_count);
uvIndices.size(), ", expected ", mapping_offsets.size());
return;
}
@ -473,6 +487,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
}
}
else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
if (!hasDataElement) {
FBXImporter::LogWarn("missing data element: ", dataElementName);
return;
}
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
@ -487,7 +506,14 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
}
else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
std::vector<T> tempData;
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
if (!hasDataElement || !hasIndexDataElement) {
if (!hasDataElement)
FBXImporter::LogWarn("missing data element: ", dataElementName);
if (!hasIndexDataElement)
FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
return;
}
ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
std::vector<int> uvIndices;
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
@ -618,10 +644,12 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
return;
}
// materials are handled separately. First of all, they are assigned per-face
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
// has a slightly different meaning for materials.
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
if (source["Materials"]) {
// materials are handled separately. First of all, they are assigned per-face
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
// has a slightly different meaning for materials.
ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
}
if (MappingInformationType == "AllSame") {
// easy - same material for all faces
@ -657,11 +685,14 @@ ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::str
DOMError("failed to read Geometry object (class: Shape), no data scope found");
}
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element);
ParseVectorDataArray(m_indices, Indexes);
ParseVectorDataArray(m_vertices, Vertices);
ParseVectorDataArray(m_normals, Normals);
if ((*sc)["Normals"]) {
const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
ParseVectorDataArray(m_normals, Normals);
}
}
// ------------------------------------------------------------------------------------------------

View file

@ -2,8 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -53,84 +52,101 @@ namespace Assimp {
namespace FBX {
/**
* DOM base class for all kinds of FBX geometry
* @brief DOM base class for all kinds of FBX geometry
*/
class Geometry : public Object {
public:
/// @brief The class constructor with all parameters.
/// @param id The id.
/// @param element
/// @param name
/// @param doc
/// @param element The element instance
/// @param name The name instance
/// @param doc The document instance
Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/// @brief The class destructor, default.
virtual ~Geometry() = default;
/// Get the Skin attached to this geometry or nullptr
/// @brief Get the Skin attached to this geometry or nullptr.
/// @return The deformer skip instance as a pointer, nullptr if none.
const Skin* DeformerSkin() const;
/// Get the BlendShape attached to this geometry or nullptr
const std::vector<const BlendShape*>& GetBlendShapes() const;
/// @brief Get the BlendShape attached to this geometry or nullptr
/// @return The blendshape arrays.
const std::unordered_set<const BlendShape*>& GetBlendShapes() const;
private:
const Skin* skin;
std::vector<const BlendShape*> blendShapes;
std::unordered_set<const BlendShape*> blendShapes;
};
typedef std::vector<int> MatIndexArray;
/**
* DOM class for FBX geometry of type "Mesh"
* @brief DOM class for FBX geometry of type "Mesh"
*/
class MeshGeometry : public Geometry {
public:
/** The class constructor */
/// @brief The class constructor
/// @param id The id.
/// @param element The element instance
/// @param name The name instance
/// @param doc The document instance
MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
/** The class destructor */
/// @brief The class destructor, default.
virtual ~MeshGeometry() = default;
/** Get a list of all vertex points, non-unique*/
/// brief Get a vector of all vertex points, non-unique.
/// @return The vertices vector.
const std::vector<aiVector3D>& GetVertices() const;
/** Get a list of all vertex normals or an empty array if
* no normals are specified. */
/// @brief Get a vector of all vertex normals or an empty array if no normals are specified.
/// @return The normal vector.
const std::vector<aiVector3D>& GetNormals() const;
/** Get a list of all vertex tangents or an empty array
* if no tangents are specified */
/// @brief Get a vector of all vertex tangents or an empty array if no tangents are specified.
/// @return The vertex tangents vector.
const std::vector<aiVector3D>& GetTangents() const;
/** Get a list of all vertex bi-normals or an empty array
* if no bi-normals are specified */
/// @brief Get a vector of all vertex bi-normals or an empty array if no bi-normals are specified.
/// @return The binomal vector.
const std::vector<aiVector3D>& GetBinormals() const;
/** Return list of faces - each entry denotes a face and specifies
* how many vertices it has. Vertices are taken from the
* vertex data arrays in sequential order. */
/// @brief Return list of faces - each entry denotes a face and specifies how many vertices it has.
/// Vertices are taken from the vertex data arrays in sequential order.
/// @return The face indices vector.
const std::vector<unsigned int>& GetFaceIndexCounts() const;
/** Get a UV coordinate slot, returns an empty array if
* the requested slot does not exist. */
/// @brief Get a UV coordinate slot, returns an empty array if the requested slot does not exist.
/// @param index The requested texture coordinate slot.
/// @return The texture coordinates.
const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const;
/** Get a UV coordinate slot, returns an empty array if
* the requested slot does not exist. */
/// @brief Get a UV coordinate slot, returns an empty array if the requested slot does not exist.
/// @param index The requested texture coordinate slot.
/// @return The texture coordinate channel name.
std::string GetTextureCoordChannelName( unsigned int index ) const;
/** Get a vertex color coordinate slot, returns an empty array if
* the requested slot does not exist. */
/// @brief Get a vertex color coordinate slot, returns an empty array if the requested slot does not exist.
/// @param index The requested texture coordinate slot.
/// @return The vertex color vector.
const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const;
/** Get per-face-vertex material assignments */
/// @brief Get per-face-vertex material assignments.
/// @return The Material indices Array.
const MatIndexArray& GetMaterialIndices() const;
/** Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr
* if the vertex index is not valid. */
/// @brief Convert from a fbx file vertex index (for example from a #Cluster weight) or nullptr if the vertex index is not valid.
/// @param in_index The requested input index.
/// @param count The number of indices.
/// @return The indices.
const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const;
/** Determine the face to which a particular output vertex index belongs.
* This mapping is always unique. */
/// @brief Determine the face to which a particular output vertex index belongs.
/// This mapping is always unique.
/// @param in_index The requested input index.
/// @return The face-to-vertex index.
unsigned int FaceForVertexIndex( unsigned int in_index ) const;
private:

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -45,12 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
//#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include "Common/Compression.h"
//# include <zlib.h>
//#else
//# include "../contrib/zlib/zlib.h"
//#endif
#include "FBXTokenizer.h"
#include "FBXParser.h"
@ -88,6 +83,7 @@ namespace {
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void ParseError(const std::string& message, TokenPtr token) AI_WONT_RETURN_SUFFIX;
void ParseError(const std::string& message, TokenPtr token)
{
if(token) {
@ -115,8 +111,11 @@ namespace Assimp {
namespace FBX {
// ------------------------------------------------------------------------------------------------
Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
Element::Element(const Token& key_token, Parser& parser) :
key_token(key_token), compound(nullptr)
{
TokenPtr n = nullptr;
StackAllocator &allocator = parser.GetAllocator();
do {
n = parser.AdvanceToNextToken();
if(!n) {
@ -145,7 +144,7 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
}
if (n->Type() == TokenType_OPEN_BRACKET) {
compound.reset(new Scope(parser));
compound = new_Scope(parser);
// current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken();
@ -163,6 +162,15 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
}
// ------------------------------------------------------------------------------------------------
Element::~Element()
{
if (compound) {
delete_Scope(compound);
}
// no need to delete tokens, they are owned by the parser
}
Scope::Scope(Parser& parser,bool topLevel)
{
if(!topLevel) {
@ -172,6 +180,7 @@ Scope::Scope(Parser& parser,bool topLevel)
}
}
StackAllocator &allocator = parser.GetAllocator();
TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) {
ParseError("unexpected end of file");
@ -187,37 +196,46 @@ Scope::Scope(Parser& parser,bool topLevel)
if (str.empty()) {
ParseError("unexpected content: empty string.");
}
elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
auto *element = new_Element(*n, parser);
// Element() should stop at the next Key token (or right after a Close token)
n = parser.CurrentToken();
if (n == nullptr) {
if (topLevel) {
elements.insert(ElementMap::value_type(str, element));
return;
}
delete_Element(element);
ParseError("unexpected end of file",parser.LastToken());
} else {
elements.insert(ElementMap::value_type(str, element));
}
}
}
// ------------------------------------------------------------------------------------------------
Scope::~Scope() {
for(ElementMap::value_type& v : elements) {
delete v.second;
Scope::~Scope()
{
// This collection does not own the memory for the elements, but we need to call their d'tor:
for (ElementMap::value_type &v : elements) {
delete_Element(v.second);
}
}
// ------------------------------------------------------------------------------------------------
Parser::Parser (const TokenList& tokens, bool is_binary)
: tokens(tokens)
, last()
, current()
, cursor(tokens.begin())
, is_binary(is_binary)
Parser::Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary) :
tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
{
ASSIMP_LOG_DEBUG("Parsing FBX tokens");
root.reset(new Scope(*this,true));
root = new_Scope(*this, true);
}
// ------------------------------------------------------------------------------------------------
Parser::~Parser()
{
delete_Scope(root);
}
// ------------------------------------------------------------------------------------------------

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/LogAux.h>
#include <assimp/fast_atof.h>
#include "Common/StackAllocator.h"
#include "FBXCompileConfig.h"
#include "FBXTokenizer.h"
@ -62,15 +63,14 @@ class Scope;
class Parser;
class Element;
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef std::vector< Scope* > ScopeList;
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
# define new_Scope new Scope
# define new_Element new Element
using ScopeList = std::vector<Scope*>;
using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;
#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
#define new_Element new (allocator.Allocate(sizeof(Element))) Element
#define delete_Scope(_p) (_p)->~Scope()
#define delete_Element(_p) (_p)->~Element()
/** FBX data entity that consists of a key:value tuple.
*
@ -82,15 +82,16 @@ typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> Element
* @endverbatim
*
* As can be seen in this sample, elements can contain nested #Scope
* as their trailing member. **/
* as their trailing member.
**/
class Element
{
public:
Element(const Token& key_token, Parser& parser);
~Element() = default;
~Element();
const Scope* Compound() const {
return compound.get();
return compound;
}
const Token& KeyToken() const {
@ -104,7 +105,7 @@ public:
private:
const Token& key_token;
TokenList tokens;
std::unique_ptr<Scope> compound;
Scope* compound;
};
/** FBX data entity that consists of a 'scope', a collection
@ -133,7 +134,7 @@ public:
const char* elementNameCStr = elementName.c_str();
for (auto element = elements.begin(); element != elements.end(); ++element)
{
if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) {
if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, AI_MAXLEN)) {
return element->second;
}
}
@ -159,17 +160,21 @@ class Parser
public:
/** Parse given a token list. Does not take ownership of the tokens -
* the objects must persist during the entire parser lifetime */
Parser (const TokenList& tokens,bool is_binary);
~Parser() = default;
Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary);
~Parser();
const Scope& GetRootScope() const {
return *root.get();
return *root;
}
bool IsBinary() const {
return is_binary;
}
StackAllocator &GetAllocator() {
return allocator;
}
private:
friend class Scope;
friend class Element;
@ -180,10 +185,10 @@ private:
private:
const TokenList& tokens;
StackAllocator &allocator;
TokenPtr last, current;
TokenList::const_iterator cursor;
std::unique_ptr<Scope> root;
Scope *root;
const bool is_binary;
};

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -243,7 +243,6 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const
// Read the element's value.
// Wrap the naked pointer (since the call site is required to acquire ownership)
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second));
// Element could not be read. Skip it.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -94,7 +94,8 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line,
// process a potential data token up to 'cur', adding it to 'output_tokens'.
// ------------------------------------------------------------------------------------------------
void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end,
void ProcessDataToken(TokenList &output_tokens, StackAllocator &token_allocator,
const char*& start, const char*& end,
unsigned int line,
unsigned int column,
TokenType type = TokenType_DATA,
@ -131,8 +132,7 @@ void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*
}
// ------------------------------------------------------------------------------------------------
void Tokenize(TokenList& output_tokens, const char* input)
{
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
ai_assert(input);
ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
@ -164,7 +164,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
in_double_quotes = false;
token_end = cur;
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
pending_data_token = false;
}
continue;
@ -181,30 +181,30 @@ void Tokenize(TokenList& output_tokens, const char* input)
continue;
case ';':
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
comment = true;
continue;
case '{':
ProcessDataToken(output_tokens,token_begin,token_end, line, column);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
continue;
case '}':
ProcessDataToken(output_tokens,token_begin,token_end,line,column);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
continue;
case ',':
if (pending_data_token) {
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
}
output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
continue;
case ':':
if (pending_data_token) {
ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
}
else {
TokenizeError("unexpected colon", line, column);
@ -226,7 +226,7 @@ void Tokenize(TokenList& output_tokens, const char* input)
}
}
ProcessDataToken(output_tokens,token_begin,token_end,line,column,type);
ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
}
pending_data_token = false;

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_TOKENIZER_H
#include "FBXCompileConfig.h"
#include "Common/StackAllocator.h"
#include <assimp/ai_assert.h>
#include <assimp/defs.h>
#include <vector>
@ -154,11 +155,11 @@ private:
const unsigned int column;
};
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
typedef const Token* TokenPtr;
typedef std::vector< TokenPtr > TokenList;
#define new_Token new Token
#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
#define delete_Token(_p) (_p)->~Token()
/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
@ -168,7 +169,7 @@ typedef std::vector< TokenPtr > TokenList;
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated.
* @throw DeadlyImportError if something goes wrong */
void Tokenize(TokenList& output_tokens, const char* input);
void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &tokenAllocator);
/** Tokenizer function for binary FBX files.
@ -179,7 +180,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
* @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal.
* @throw DeadlyImportError if something goes wrong */
void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &tokenAllocator);
} // ! FBX

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -155,7 +155,7 @@ size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOut
const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
size_t dst_offset = 0;
int val = 0, valb = -8;
for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
for (size_t src_offset = 0; src_offset < realLength && dst_offset < maxOutLength; ++src_offset)
{
const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
if (table_value == 255)

View file

@ -2,7 +2,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
Copyright (c) 2006-2024, assimp team
All rights reserved.
@ -66,6 +66,17 @@ struct delete_fun
}
};
/** helper for std::for_each to call the destructor on all items in a container without freeing their heap*/
template <typename T>
struct destructor_fun {
void operator()(const volatile T* del) {
if (del) {
del->~T();
}
}
};
/** Get a string representation for a #TokenType. */
const char* TokenTypeString(TokenType t);