Skip to content

Commit

Permalink
Merge branch 'master' into add-msvc-check
Browse files Browse the repository at this point in the history
  • Loading branch information
kimkulling authored Dec 11, 2020
2 parents 8d8ba52 + 80bb8ab commit a2adef8
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 149 deletions.
12 changes: 9 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,15 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ENDIF()
# hide all not-exported symbols
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSE()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
SET(LIBSTDC++_LIBRARIES -lstdc++)
ENDIF()
ELSEIF(MSVC)
# enable multi-core compilation with MSVC
IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl
Expand Down
11 changes: 7 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ A library to import and export various 3d-model-formats including scene-post-pro
<br>

APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.

[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).

Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.

This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
### Latest Doc's ###
Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/).

### Get involved ###
This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
<br>
You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
<br>
Please check our Wiki as well: https://github.com/assimp/assimp/wiki

If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
Expand Down
217 changes: 110 additions & 107 deletions code/AssetLib/FBX/FBXConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,144 +185,147 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
return unique_name;
}

/// This struct manages nodes which may or may not end up in the node hierarchy.
/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
struct FBXConverter::PotentialNode
{
PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
aiNode* operator->() { return mNode; }
std::unique_ptr<aiNode> mOwnership;
aiNode* mNode;
};

/// todo: pre-build node hierarchy
/// 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) {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");

std::vector<aiNode *> nodes;
std::vector<PotentialNode> nodes;
nodes.reserve(conns.size());

std::vector<aiNode *> nodes_chain;
std::vector<aiNode *> post_nodes_chain;

try {
for (const Connection *con : conns) {
// ignore object-property links
if (con->PropertyName().length()) {
// really important we document why this is ignored.
FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
continue; //?
}

// convert connection source object into Object base class
const Object *const object = con->SourceObject();
if (nullptr == object) {
FBXImporter::LogError("failed to convert source object for Model link");
continue;
}
std::vector<PotentialNode> nodes_chain;
std::vector<PotentialNode> post_nodes_chain;

// FBX Model::Cube, Model::Bone001, etc elements
// This detects if we can cast the object into this model structure.
const Model *const model = dynamic_cast<const Model *>(object);
for (const Connection *con : conns) {
// ignore object-property links
if (con->PropertyName().length()) {
// really important we document why this is ignored.
FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
continue; //?
}

if (nullptr != model) {
nodes_chain.clear();
post_nodes_chain.clear();
// convert connection source object into Object base class
const Object *const object = con->SourceObject();
if (nullptr == object) {
FBXImporter::LogError("failed to convert source object for Model link");
continue;
}

aiMatrix4x4 new_abs_transform = parent->mTransformation;
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
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.
// FBX Model::Cube, Model::Bone001, etc elements
// This detects if we can cast the object into this model structure.
const Model *const model = dynamic_cast<const Model *>(object);

// generate node transforms - this includes pivot data
// if need_additional_node is true then you t
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
if (nullptr != model) {
nodes_chain.clear();
post_nodes_chain.clear();

// assert that for the current node we must have at least a single transform
ai_assert(nodes_chain.size());
aiMatrix4x4 new_abs_transform = parent->mTransformation;
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
// is employed by fbx) means that we may need multiple aiNode's
// to represent a fbx node's transformation.

if (need_additional_node) {
nodes_chain.push_back(new aiNode(node_name));
}
// generate node transforms - this includes pivot data
// if need_additional_node is true then you t
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);

//setup metadata on newest node
SetupNodeMetadata(*model, *nodes_chain.back());
// assert that for the current node we must have at least a single transform
ai_assert(nodes_chain.size());

// link all nodes in a row
aiNode *last_parent = parent;
for (aiNode *child : nodes_chain) {
ai_assert(child);
if (need_additional_node) {
nodes_chain.emplace_back(PotentialNode(node_name));
}

if (last_parent != parent) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = child;
}
//setup metadata on newest node
SetupNodeMetadata(*model, *nodes_chain.back().mNode);

child->mParent = last_parent;
last_parent = child;
// link all nodes in a row
aiNode *last_parent = parent;
for (PotentialNode& child : nodes_chain) {
ai_assert(child.mNode);

new_abs_transform *= child->mTransformation;
if (last_parent != parent) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = child.mOwnership.release();
}

// attach geometry
ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
child->mParent = last_parent;
last_parent = child.mNode;

// check if there will be any child nodes
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
new_abs_transform *= child->mTransformation;
}

// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for (aiNode *postnode : post_nodes_chain) {
ai_assert(postnode);
// attach geometry
ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);

if (last_parent != parent) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = postnode;
}
// check if there will be any child nodes
const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");

postnode->mParent = last_parent;
last_parent = postnode;
// if so, link the geometric transform inverse nodes
// before we attach any child nodes
if (child_conns.size()) {
for (PotentialNode& postnode : post_nodes_chain) {
ai_assert(postnode.mNode);

new_abs_transform *= postnode->mTransformation;
if (last_parent != parent) {
last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode *[1];
last_parent->mChildren[0] = postnode.mOwnership.release();
}
} else {
// free the nodes we allocated as we don't need them
Util::delete_fun<aiNode> deleter;
std::for_each(
post_nodes_chain.begin(),
post_nodes_chain.end(),
deleter);
}

// recursion call - child nodes
ConvertNodes(model->ID(), last_parent, root_node);
postnode->mParent = last_parent;
last_parent = postnode.mNode;

if (doc.Settings().readLights) {
ConvertLights(*model, node_name);
new_abs_transform *= postnode->mTransformation;
}
} else {
// free the nodes we allocated as we don't need them
post_nodes_chain.clear();
}

if (doc.Settings().readCameras) {
ConvertCameras(*model, node_name);
}
// recursion call - child nodes
ConvertNodes(model->ID(), last_parent, root_node);

nodes.push_back(nodes_chain.front());
nodes_chain.clear();
if (doc.Settings().readLights) {
ConvertLights(*model, node_name);
}
}

if (nodes.size()) {
parent->mChildren = new aiNode *[nodes.size()]();
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
if (doc.Settings().readCameras) {
ConvertCameras(*model, node_name);
}

std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
} else {
parent->mNumChildren = 0;
parent->mChildren = nullptr;
nodes.push_back(std::move(nodes_chain.front()));
nodes_chain.clear();
}
}

} catch (std::exception &) {
Util::delete_fun<aiNode> deleter;
std::for_each(nodes.begin(), nodes.end(), deleter);
std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
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 {
parent->mNumChildren = 0;
parent->mChildren = nullptr;
}
}

Expand Down Expand Up @@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T
return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
}

bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<aiNode *> &output_nodes,
std::vector<aiNode *> &post_output_nodes) {
bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<PotentialNode> &output_nodes,
std::vector<PotentialNode> &post_output_nodes) {
const PropertyTable &props = model.Props();
const Model::RotOrder rot = model.RotationOrder();

Expand Down Expand Up @@ -828,17 +831,17 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
chain[i] = chain[i].Inverse();
}

aiNode *nd = new aiNode();
PotentialNode nd;
nd->mName.Set(NameTransformationChainNode(name, comp));
nd->mTransformation = chain[i];

// geometric inverses go in a post-node chain
if (comp == TransformationComp_GeometricScalingInverse ||
comp == TransformationComp_GeometricRotationInverse ||
comp == TransformationComp_GeometricTranslationInverse) {
post_output_nodes.push_back(nd);
post_output_nodes.emplace_back(std::move(nd));
} else {
output_nodes.push_back(nd);
output_nodes.emplace_back(std::move(nd));
}
}

Expand All @@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
}

// else, we can just multiply the matrices together
aiNode *nd = new aiNode();
output_nodes.push_back(nd);
PotentialNode nd;

// name passed to the method is already unique
nd->mName.Set(name);
Expand All @@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
nd->mTransformation = nd->mTransformation * chain[i];
}
output_nodes.push_back(std::move(nd));
return false;
}

Expand Down
5 changes: 3 additions & 2 deletions code/AssetLib/FBX/FBXConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,10 @@ class FBXConverter {

// ------------------------------------------------------------------------------------------------
/**
* note: memory for output_nodes will be managed by the caller
* note: memory for output_nodes is managed by the caller, via the PotentialNode struct.
*/
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
struct PotentialNode;
bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<PotentialNode>& output_nodes, std::vector<PotentialNode>& post_output_nodes);

// ------------------------------------------------------------------------------------------------
void SetupNodeMetadata(const Model& model, aiNode& nd);
Expand Down
4 changes: 3 additions & 1 deletion code/AssetLib/glTF/glTFCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ using namespace glTFCommon::Util;
namespace Util {

size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out) {
ai_assert(inLength % 4 == 0);
if (inLength % 4 != 0) {
throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength);
}

if (inLength < 4) {
out = 0;
Expand Down
5 changes: 4 additions & 1 deletion code/AssetLib/glTF/glTFCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,10 @@ inline char EncodeCharBase64(uint8_t b) {
}

inline uint8_t DecodeCharBase64(char c) {
return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
if (c & 0x80) {
throw DeadlyImportError("Invalid base64 char value: ", size_t(c));
}
return DATA<true>::tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs?
}

size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out);
Expand Down
8 changes: 8 additions & 0 deletions code/AssetLib/glTF2/glTF2Asset.h
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,14 @@ class Asset {
IOStream *OpenFile(std::string path, const char *mode, bool absolute = false);
};

inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {
std::string context = id;
if (!name.empty()) {
context += " (\"" + name + "\")";
}
return context;
}

} // namespace glTF2

// Include the implementation of the methods
Expand Down
Loading

0 comments on commit a2adef8

Please sign in to comment.