diff --git a/code/FBX/FBXConverter.cpp b/code/FBX/FBXConverter.cpp index 26a3c4b99..5b34868ba 100644 --- a/code/FBX/FBXConverter.cpp +++ b/code/FBX/FBXConverter.cpp @@ -2088,7 +2088,14 @@ namespace Assimp { TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + + // 3DSMax PBR + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); } void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) diff --git a/code/PostProcessing/ConvertToLHProcess.h b/code/PostProcessing/ConvertToLHProcess.h index f32b91fc3..0c4a3a091 100644 --- a/code/PostProcessing/ConvertToLHProcess.h +++ b/code/PostProcessing/ConvertToLHProcess.h @@ -137,8 +137,9 @@ public: // ------------------------------------------------------------------- void Execute( aiScene* pScene); -protected: - void ProcessMesh( aiMesh* pMesh); +public: + /** Some other types of post-processing require winding order flips */ + static void ProcessMesh( aiMesh* pMesh); }; // --------------------------------------------------------------------------- diff --git a/code/PostProcessing/OptimizeGraph.cpp b/code/PostProcessing/OptimizeGraph.cpp index 5db51f58b..43bd7a3ee 100644 --- a/code/PostProcessing/OptimizeGraph.cpp +++ b/code/PostProcessing/OptimizeGraph.cpp @@ -43,13 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the aiProcess_OptimizGraph step */ - #ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS #include "OptimizeGraph.h" #include "ProcessHelper.h" -#include +#include "ConvertToLHProcess.h" #include +#include #include using namespace Assimp; @@ -60,292 +60,299 @@ using namespace Assimp; * The unhashed variant should be faster, except for *very* large data sets */ #ifdef AI_OG_USE_HASHING - // Use our standard hashing function to compute the hash -# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length) +// Use our standard hashing function to compute the hash +#define AI_OG_GETKEY(str) SuperFastHash(str.data, str.length) #else - // Otherwise hope that std::string will utilize a static buffer - // for shorter node names. This would avoid endless heap copying. -# define AI_OG_GETKEY(str) std::string(str.data) +// Otherwise hope that std::string will utilize a static buffer +// for shorter node names. This would avoid endless heap copying. +#define AI_OG_GETKEY(str) std::string(str.data) #endif // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -OptimizeGraphProcess::OptimizeGraphProcess() -: mScene() -, nodes_in() -, nodes_out() -, count_merged() { - // empty +OptimizeGraphProcess::OptimizeGraphProcess() : + mScene(), + nodes_in(), + nodes_out(), + count_merged() { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well OptimizeGraphProcess::~OptimizeGraphProcess() { - // empty + // empty } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const { - return (0 != (pFlags & aiProcess_OptimizeGraph)); +bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const { + return (0 != (pFlags & aiProcess_OptimizeGraph)); } // ------------------------------------------------------------------------------------------------ // Setup properties for the post-processing step -void OptimizeGraphProcess::SetupProperties(const Importer* pImp) { - // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST - std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,""); - AddLockedNodeList(tmp); +void OptimizeGraphProcess::SetupProperties(const Importer *pImp) { + // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST + std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST, ""); + AddLockedNodeList(tmp); } // ------------------------------------------------------------------------------------------------ // Collect new children -void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list& nodes) { - nodes_in += nd->mNumChildren; +void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list &nodes) { + nodes_in += nd->mNumChildren; - // Process children - std::list child_nodes; - for (unsigned int i = 0; i < nd->mNumChildren; ++i) { - CollectNewChildren(nd->mChildren[i],child_nodes); - nd->mChildren[i] = nullptr; - } + // Process children + std::list child_nodes; + for (unsigned int i = 0; i < nd->mNumChildren; ++i) { + CollectNewChildren(nd->mChildren[i], child_nodes); + nd->mChildren[i] = nullptr; + } - // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest). - if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) { - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { + // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest). + if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end()) { + for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { - if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) { - (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation; - nodes.push_back(*it); + if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) { + (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation; + nodes.push_back(*it); - it = child_nodes.erase(it); - continue; - } - ++it; - } + it = child_nodes.erase(it); + continue; + } + ++it; + } - if (nd->mNumMeshes || !child_nodes.empty()) { - nodes.push_back(nd); - } else { - delete nd; /* bye, node */ - return; - } - } else { + if (nd->mNumMeshes || !child_nodes.empty()) { + nodes.push_back(nd); + } else { + delete nd; /* bye, node */ + return; + } + } else { - // Retain our current position in the hierarchy - nodes.push_back(nd); + // Retain our current position in the hierarchy + nodes.push_back(nd); - // Now check for possible optimizations in our list of child nodes. join as many as possible - aiNode* join_master = NULL; - aiMatrix4x4 inv; + // Now check for possible optimizations in our list of child nodes. join as many as possible + aiNode *join_master = nullptr; + aiMatrix4x4 inv; - const LockedSetType::const_iterator end = locked.end(); + const LockedSetType::const_iterator end = locked.end(); - std::list join; - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { - aiNode* child = *it; - if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) { + std::list join; + for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end();) { + aiNode *child = *it; + if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) { - // There may be no instanced meshes - unsigned int n = 0; - for (; n < child->mNumMeshes;++n) { - if (meshes[child->mMeshes[n]] > 1) { - break; - } - } - if (n == child->mNumMeshes) { - if (!join_master) { - join_master = child; - inv = join_master->mTransformation; - inv.Inverse(); - } else { - child->mTransformation = inv * child->mTransformation ; + // There may be no instanced meshes + unsigned int n = 0; + for (; n < child->mNumMeshes; ++n) { + if (meshes[child->mMeshes[n]] > 1) { + break; + } + } + if (n == child->mNumMeshes) { + if (!join_master) { + join_master = child; + inv = join_master->mTransformation; + inv.Inverse(); + } else { + child->mTransformation = inv * child->mTransformation; - join.push_back(child); - it = child_nodes.erase(it); - continue; - } - } - } - ++it; - } - if (join_master && !join.empty()) { - join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++); + join.push_back(child); + it = child_nodes.erase(it); + continue; + } + } + } + ++it; + } + if (join_master && !join.empty()) { + join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++); - unsigned int out_meshes = 0; - for (std::list::iterator it = join.begin(); it != join.end(); ++it) { - out_meshes += (*it)->mNumMeshes; - } + unsigned int out_meshes = 0; + for (std::list::const_iterator it = join.cbegin(); it != join.cend(); ++it) { + out_meshes += (*it)->mNumMeshes; + } - // copy all mesh references in one array - if (out_meshes) { - unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes; - for (unsigned int n = 0; n < join_master->mNumMeshes;++n) { - *tmp++ = join_master->mMeshes[n]; - } + // copy all mesh references in one array + if (out_meshes) { + unsigned int *meshes = new unsigned int[out_meshes + join_master->mNumMeshes], *tmp = meshes; + for (unsigned int n = 0; n < join_master->mNumMeshes; ++n) { + *tmp++ = join_master->mMeshes[n]; + } - for (std::list::iterator it = join.begin(); it != join.end(); ++it) { - for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) { + for (const aiNode *join_node : join) { + for (unsigned int n = 0; n < join_node->mNumMeshes; ++n) { - *tmp = (*it)->mMeshes[n]; - aiMesh* mesh = mScene->mMeshes[*tmp++]; + *tmp = join_node->mMeshes[n]; + aiMesh *mesh = mScene->mMeshes[*tmp++]; - // manually move the mesh into the right coordinate system - const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose(); - for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { + // Assume the transformation is affine + // manually move the mesh into the right coordinate system - mesh->mVertices[a] *= (*it)->mTransformation; + // Check for odd negative scale (mirror) + if (join_node->mTransformation.Determinant() < 0) { + // Reverse the mesh face winding order + FlipWindingOrderProcess::ProcessMesh(mesh); + } - if (mesh->HasNormals()) - mesh->mNormals[a] *= IT; + // Update positions, normals and tangents + const aiMatrix3x3 IT = aiMatrix3x3(join_node->mTransformation).Inverse().Transpose(); + for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { - if (mesh->HasTangentsAndBitangents()) { - mesh->mTangents[a] *= IT; - mesh->mBitangents[a] *= IT; - } - } - } - delete *it; // bye, node - } - delete[] join_master->mMeshes; - join_master->mMeshes = meshes; - join_master->mNumMeshes += out_meshes; - } - } - } - // reassign children if something changed - if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) { + mesh->mVertices[a] *= join_node->mTransformation; - delete[] nd->mChildren; + if (mesh->HasNormals()) + mesh->mNormals[a] *= IT; - if (!child_nodes.empty()) { - nd->mChildren = new aiNode*[child_nodes.size()]; - } - else nd->mChildren = nullptr; - } + if (mesh->HasTangentsAndBitangents()) { + mesh->mTangents[a] *= IT; + mesh->mBitangents[a] *= IT; + } + } + } + delete join_node; // bye, node + } + delete[] join_master->mMeshes; + join_master->mMeshes = meshes; + join_master->mNumMeshes += out_meshes; + } + } + } + // reassign children if something changed + if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) { - nd->mNumChildren = static_cast(child_nodes.size()); + delete[] nd->mChildren; - if (nd->mChildren) { - aiNode** tmp = nd->mChildren; - for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) { - aiNode* node = *tmp++ = *it; - node->mParent = nd; - } - } + if (!child_nodes.empty()) { + nd->mChildren = new aiNode *[child_nodes.size()]; + } else + nd->mChildren = nullptr; + } - nodes_out += static_cast(child_nodes.size()); + nd->mNumChildren = static_cast(child_nodes.size()); + + if (nd->mChildren) { + aiNode **tmp = nd->mChildren; + for (std::list::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) { + aiNode *node = *tmp++ = *it; + node->mParent = nd; + } + } + + nodes_out += static_cast(child_nodes.size()); } // ------------------------------------------------------------------------------------------------ // Execute the post-processing step on the given scene -void OptimizeGraphProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin"); - nodes_in = nodes_out = count_merged = 0; - mScene = pScene; +void OptimizeGraphProcess::Execute(aiScene *pScene) { + ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin"); + nodes_in = nodes_out = count_merged = 0; + mScene = pScene; - meshes.resize(pScene->mNumMeshes,0); - FindInstancedMeshes(pScene->mRootNode); + meshes.resize(pScene->mNumMeshes, 0); + FindInstancedMeshes(pScene->mRootNode); - // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it - locked.clear(); - for (std::list::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) { + // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it + locked.clear(); + for (std::list::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) { #ifdef AI_OG_USE_HASHING - locked.insert(SuperFastHash((*it).c_str())); + locked.insert(SuperFastHash((*it).c_str())); #else - locked.insert(*it); + locked.insert(*it); #endif - } + } - for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { - for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) { - aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a]; - locked.insert(AI_OG_GETKEY(anim->mNodeName)); - } - } + for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { + for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) { + aiNodeAnim *anim = pScene->mAnimations[i]->mChannels[a]; + locked.insert(AI_OG_GETKEY(anim->mNodeName)); + } + } - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) { + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) { - aiBone* bone = pScene->mMeshes[i]->mBones[a]; - locked.insert(AI_OG_GETKEY(bone->mName)); + aiBone *bone = pScene->mMeshes[i]->mBones[a]; + locked.insert(AI_OG_GETKEY(bone->mName)); - // HACK: Meshes referencing bones may not be transformed; we need to look them. - // The easiest way to do this is to increase their reference counters ... - meshes[i] += 2; - } - } + // HACK: Meshes referencing bones may not be transformed; we need to look them. + // The easiest way to do this is to increase their reference counters ... + meshes[i] += 2; + } + } - for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { - aiCamera* cam = pScene->mCameras[i]; - locked.insert(AI_OG_GETKEY(cam->mName)); - } + for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { + aiCamera *cam = pScene->mCameras[i]; + locked.insert(AI_OG_GETKEY(cam->mName)); + } - for (unsigned int i = 0; i < pScene->mNumLights; ++i) { - aiLight* lgh = pScene->mLights[i]; - locked.insert(AI_OG_GETKEY(lgh->mName)); - } + for (unsigned int i = 0; i < pScene->mNumLights; ++i) { + aiLight *lgh = pScene->mLights[i]; + locked.insert(AI_OG_GETKEY(lgh->mName)); + } - // Insert a dummy master node and make it read-only - aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME); - locked.insert(AI_OG_GETKEY(dummy_root->mName)); + // Insert a dummy master node and make it read-only + aiNode *dummy_root = new aiNode(AI_RESERVED_NODE_NAME); + locked.insert(AI_OG_GETKEY(dummy_root->mName)); - const aiString prev = pScene->mRootNode->mName; - pScene->mRootNode->mParent = dummy_root; + const aiString prev = pScene->mRootNode->mName; + pScene->mRootNode->mParent = dummy_root; - dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1]; - dummy_root->mChildren[0] = pScene->mRootNode; + dummy_root->mChildren = new aiNode *[dummy_root->mNumChildren = 1]; + dummy_root->mChildren[0] = pScene->mRootNode; - // Do our recursive processing of scenegraph nodes. For each node collect - // a fully new list of children and allow their children to place themselves - // on the same hierarchy layer as their parents. - std::list nodes; - CollectNewChildren (dummy_root,nodes); + // Do our recursive processing of scenegraph nodes. For each node collect + // a fully new list of children and allow their children to place themselves + // on the same hierarchy layer as their parents. + std::list nodes; + CollectNewChildren(dummy_root, nodes); - ai_assert(nodes.size() == 1); + ai_assert(nodes.size() == 1); - if (dummy_root->mNumChildren == 0) { - pScene->mRootNode = NULL; - throw DeadlyImportError("After optimizing the scene graph, no data remains"); - } + if (dummy_root->mNumChildren == 0) { + pScene->mRootNode = nullptr; + throw DeadlyImportError("After optimizing the scene graph, no data remains"); + } - if (dummy_root->mNumChildren > 1) { - pScene->mRootNode = dummy_root; + if (dummy_root->mNumChildren > 1) { + pScene->mRootNode = dummy_root; - // Keep the dummy node but assign the name of the old root node to it - pScene->mRootNode->mName = prev; - } - else { + // Keep the dummy node but assign the name of the old root node to it + pScene->mRootNode->mName = prev; + } else { - // Remove the dummy root node again. - pScene->mRootNode = dummy_root->mChildren[0]; + // Remove the dummy root node again. + pScene->mRootNode = dummy_root->mChildren[0]; - dummy_root->mChildren[0] = NULL; - delete dummy_root; - } + dummy_root->mChildren[0] = nullptr; + delete dummy_root; + } - pScene->mRootNode->mParent = NULL; - if (!DefaultLogger::isNullLogger()) { - if ( nodes_in != nodes_out) { - ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out); - } else { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished"); - } - } - meshes.clear(); - locked.clear(); + pScene->mRootNode->mParent = nullptr; + if (!DefaultLogger::isNullLogger()) { + if (nodes_in != nodes_out) { + ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out); + } else { + ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished"); + } + } + meshes.clear(); + locked.clear(); } // ------------------------------------------------------------------------------------------------ // Build a LUT of all instanced meshes -void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode) -{ - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - ++meshes[pNode->mMeshes[i]]; - } +void OptimizeGraphProcess::FindInstancedMeshes(aiNode *pNode) { + for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) { + ++meshes[pNode->mMeshes[i]]; + } - for (unsigned int i = 0; i < pNode->mNumChildren; ++i) - FindInstancedMeshes(pNode->mChildren[i]); + for (unsigned int i = 0; i < pNode->mNumChildren; ++i) + FindInstancedMeshes(pNode->mChildren[i]); } #endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS diff --git a/code/PostProcessing/OptimizeGraph.h b/code/PostProcessing/OptimizeGraph.h index 82cc5db3f..d2a6de9a2 100644 --- a/code/PostProcessing/OptimizeGraph.h +++ b/code/PostProcessing/OptimizeGraph.h @@ -75,13 +75,13 @@ public: ~OptimizeGraphProcess(); // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** @brief Add a list of node names to be locked and not modified. diff --git a/code/PostProcessing/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp index 52001a057..fb6b458d8 100644 --- a/code/PostProcessing/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -45,11 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the "PretransformVertices" post processing step */ - #include "PretransformVertices.h" +#include "ConvertToLHProcess.h" #include "ProcessHelper.h" -#include #include +#include using namespace Assimp; @@ -59,670 +59,630 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -PretransformVertices::PretransformVertices() -: configKeepHierarchy (false) -, configNormalize(false) -, configTransform(false) -, configTransformation() -, mConfigPointCloud( false ) { - // empty +PretransformVertices::PretransformVertices() : + configKeepHierarchy(false), + configNormalize(false), + configTransform(false), + configTransformation(), + mConfigPointCloud(false) { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well PretransformVertices::~PretransformVertices() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool PretransformVertices::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_PreTransformVertices) != 0; +bool PretransformVertices::IsActive(unsigned int pFlags) const { + return (pFlags & aiProcess_PreTransformVertices) != 0; } // ------------------------------------------------------------------------------------------------ // Setup import configuration -void PretransformVertices::SetupProperties(const Importer* pImp) -{ - // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, - // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION - configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0)); - configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0)); - configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0)); +void PretransformVertices::SetupProperties(const Importer *pImp) { + // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, + // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION + configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0)); + configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0)); + configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0)); - configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); + configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); - mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); + mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); } // ------------------------------------------------------------------------------------------------ // Count the number of nodes -unsigned int PretransformVertices::CountNodes( aiNode* pcNode ) -{ - unsigned int iRet = 1; - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - iRet += CountNodes(pcNode->mChildren[i]); - } - return iRet; +unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const { + unsigned int iRet = 1; + for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { + iRet += CountNodes(pcNode->mChildren[i]); + } + return iRet; } // ------------------------------------------------------------------------------------------------ // Get a bitwise combination identifying the vertex format of a mesh -unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh ) -{ - // the vertex format is stored in aiMesh::mBones for later retrieval. - // there isn't a good reason to compute it a few hundred times - // from scratch. The pointer is unused as animations are lost - // during PretransformVertices. - if (pcMesh->mBones) - return (unsigned int)(uint64_t)pcMesh->mBones; +unsigned int PretransformVertices::GetMeshVFormat(aiMesh *pcMesh) const { + // the vertex format is stored in aiMesh::mBones for later retrieval. + // there isn't a good reason to compute it a few hundred times + // from scratch. The pointer is unused as animations are lost + // during PretransformVertices. + if (pcMesh->mBones) + return (unsigned int)(uint64_t)pcMesh->mBones; + const unsigned int iRet = GetMeshVFormatUnique(pcMesh); - const unsigned int iRet = GetMeshVFormatUnique(pcMesh); - - // store the value for later use - pcMesh->mBones = (aiBone**)(uint64_t)iRet; - return iRet; + // store the value for later use + pcMesh->mBones = (aiBone **)(uint64_t)iRet; + return iRet; } // ------------------------------------------------------------------------------------------------ // Count the number of vertices in the whole scene and a given // material index -void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices) -{ - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - *piVertices += pcMesh->mNumVertices; - *piFaces += pcMesh->mNumFaces; - } - } - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat, - iVFormat,piFaces,piVertices); - } +void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat, + unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const { + for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) { + aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]]; + if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) { + *piVertices += pcMesh->mNumVertices; + *piFaces += pcMesh->mNumFaces; + } + } + for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { + CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, + iVFormat, piFaces, piVertices); + } } // ------------------------------------------------------------------------------------------------ // Collect vertex/face data -void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, aiMesh* pcMeshOut, - unsigned int aiCurrent[2], unsigned int* num_refs) -{ - // No need to multiply if there's no transformation - const bool identity = pcNode->mTransformation.IsIdentity(); - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - // Decrement mesh reference counter - unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; - ai_assert(0 != num_ref); - --num_ref; - // Save the name of the last mesh - if (num_ref==0) - { - pcMeshOut->mName = pcMesh->mName; - } +void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat, + unsigned int iVFormat, aiMesh *pcMeshOut, + unsigned int aiCurrent[2], unsigned int *num_refs) const { + // No need to multiply if there's no transformation + const bool identity = pcNode->mTransformation.IsIdentity(); + for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) { + aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]]; + if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) { + // Decrement mesh reference counter + unsigned int &num_ref = num_refs[pcNode->mMeshes[i]]; + ai_assert(0 != num_ref); + --num_ref; + // Save the name of the last mesh + if (num_ref == 0) { + pcMeshOut->mName = pcMesh->mName; + } - if (identity) { - // copy positions without modifying them - ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mVertices, - pcMesh->mNumVertices * sizeof(aiVector3D)); + if (identity) { + // copy positions without modifying them + ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mVertices, + pcMesh->mNumVertices * sizeof(aiVector3D)); - if (iVFormat & 0x2) { - // copy normals without modifying them - ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mNormals, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - if (iVFormat & 0x4) - { - // copy tangents without modifying them - ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - // copy bitangents without modifying them - ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mBitangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - } - else - { - // copy positions, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n]; - } - aiMatrix4x4 mWorldIT = pcNode->mTransformation; - mWorldIT.Inverse().Transpose(); + if (iVFormat & 0x2) { + // copy normals without modifying them + ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mNormals, + pcMesh->mNumVertices * sizeof(aiVector3D)); + } + if (iVFormat & 0x4) { + // copy tangents without modifying them + ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mTangents, + pcMesh->mNumVertices * sizeof(aiVector3D)); + // copy bitangents without modifying them + ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mBitangents, + pcMesh->mNumVertices * sizeof(aiVector3D)); + } + } else { + // copy positions, transform them to worldspace + for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { + pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX] + n] = pcNode->mTransformation * pcMesh->mVertices[n]; + } + aiMatrix4x4 mWorldIT = pcNode->mTransformation; + mWorldIT.Inverse().Transpose(); - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); + // TODO: implement Inverse() for aiMatrix3x3 + aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - if (iVFormat & 0x2) - { - // copy normals, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = - (m * pcMesh->mNormals[n]).Normalize(); - } - } - if (iVFormat & 0x4) - { - // copy tangents and bitangents, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize(); - pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize(); - } - } - } - unsigned int p = 0; - while (iVFormat & (0x100 << p)) - { - // copy texture coordinates - memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTextureCoords[p], - pcMesh->mNumVertices * sizeof(aiVector3D)); - ++p; - } - p = 0; - while (iVFormat & (0x1000000 << p)) - { - // copy vertex colors - memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mColors[p], - pcMesh->mNumVertices * sizeof(aiColor4D)); - ++p; - } - // now we need to copy all faces. since we will delete the source mesh afterwards, - // we don't need to reallocate the array of indices except if this mesh is - // referenced multiple times. - for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck) - { - aiFace& f_src = pcMesh->mFaces[planck]; - aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck]; + if (iVFormat & 0x2) { + // copy normals, transform them to worldspace + for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { + pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX] + n] = + (m * pcMesh->mNormals[n]).Normalize(); + } + } + if (iVFormat & 0x4) { + // copy tangents and bitangents, transform them to worldspace + for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) { + pcMeshOut->mTangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mTangents[n]).Normalize(); + pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mBitangents[n]).Normalize(); + } + } + } + unsigned int p = 0; + while (iVFormat & (0x100 << p)) { + // copy texture coordinates + memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mTextureCoords[p], + pcMesh->mNumVertices * sizeof(aiVector3D)); + ++p; + } + p = 0; + while (iVFormat & (0x1000000 << p)) { + // copy vertex colors + memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mColors[p], + pcMesh->mNumVertices * sizeof(aiColor4D)); + ++p; + } + // now we need to copy all faces. since we will delete the source mesh afterwards, + // we don't need to reallocate the array of indices except if this mesh is + // referenced multiple times. + for (unsigned int planck = 0; planck < pcMesh->mNumFaces; ++planck) { + aiFace &f_src = pcMesh->mFaces[planck]; + aiFace &f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE] + planck]; - const unsigned int num_idx = f_src.mNumIndices; + const unsigned int num_idx = f_src.mNumIndices; - f_dst.mNumIndices = num_idx; + f_dst.mNumIndices = num_idx; - unsigned int* pi; - if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */ - pi = f_dst.mIndices = f_src.mIndices; + unsigned int *pi; + if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */ + pi = f_dst.mIndices = f_src.mIndices; - // offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; - } - } - else { - pi = f_dst.mIndices = new unsigned int[num_idx]; + // offset all vertex indices + for (unsigned int hahn = 0; hahn < num_idx; ++hahn) { + pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; + } + } else { + pi = f_dst.mIndices = new unsigned int[num_idx]; - // copy and offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX]; - } - } + // copy and offset all vertex indices + for (unsigned int hahn = 0; hahn < num_idx; ++hahn) { + pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX]; + } + } - // Update the mPrimitiveTypes member of the mesh - switch (pcMesh->mFaces[planck].mNumIndices) - { - case 0x1: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 0x2: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 0x3: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; - } - aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices; - aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; - } - } + // Update the mPrimitiveTypes member of the mesh + switch (pcMesh->mFaces[planck].mNumIndices) { + case 0x1: + pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 0x2: + pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 0x3: + pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + }; + } + aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices; + aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; + } + } - // append all children of us - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - CollectData(pcScene,pcNode->mChildren[i],iMat, - iVFormat,pcMeshOut,aiCurrent,num_refs); - } + // append all children of us + for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { + CollectData(pcScene, pcNode->mChildren[i], iMat, + iVFormat, pcMeshOut, aiCurrent, num_refs); + } } // ------------------------------------------------------------------------------------------------ // Get a list of all vertex formats that occur for a given material index // The output list contains duplicate elements -void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list& aiOut) -{ - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ i ]; - if (iMat == pcMesh->mMaterialIndex) { - aiOut.push_back(GetMeshVFormat(pcMesh)); - } - } +void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat, + std::list &aiOut) const { + for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) { + aiMesh *pcMesh = pcScene->mMeshes[i]; + if (iMat == pcMesh->mMaterialIndex) { + aiOut.push_back(GetMeshVFormat(pcMesh)); + } + } } // ------------------------------------------------------------------------------------------------ // Compute the absolute transformation matrices of each node -void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode ) -{ - if (pcNode->mParent) { - pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation; - } +void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) { + if (pcNode->mParent) { + pcNode->mTransformation = pcNode->mParent->mTransformation * pcNode->mTransformation; + } - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - ComputeAbsoluteTransform(pcNode->mChildren[i]); - } + for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { + ComputeAbsoluteTransform(pcNode->mChildren[i]); + } } // ------------------------------------------------------------------------------------------------ // Apply the node transformation to a mesh -void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat) -{ - // Check whether we need to transform the coordinates at all - if (!mat.IsIdentity()) { +void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const { + // Check whether we need to transform the coordinates at all + if (!mat.IsIdentity()) { - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - aiMatrix4x4 mWorldIT = mat; - mWorldIT.Inverse().Transpose(); + // Check for odd negative scale (mirror) + if (mesh->HasFaces() && mat.Determinant() < 0) { + // Reverse the mesh face winding order + FlipWindingOrderProcess::ProcessMesh(mesh); + } - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); + // Update positions + if (mesh->HasPositions()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mVertices[i] = mat * mesh->mVertices[i]; + } + } - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } - } - } - } + // Update normals and tangents + if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { + const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose(); + + if (mesh->HasNormals()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); + } + } + if (mesh->HasTangentsAndBitangents()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); + mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); + } + } + } + } } // ------------------------------------------------------------------------------------------------ // Simple routine to build meshes in worldspace, no further optimization -void PretransformVertices::BuildWCSMeshes(std::vector& out, aiMesh** in, - unsigned int numIn, aiNode* node) -{ - // NOTE: - // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy - // aiMesh::mBones store reference to abs. transform we multiplied with +void PretransformVertices::BuildWCSMeshes(std::vector &out, aiMesh **in, + unsigned int numIn, aiNode *node) const { + // NOTE: + // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy + // aiMesh::mBones store reference to abs. transform we multiplied with - // process meshes - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - aiMesh* mesh = in[node->mMeshes[i]]; + // process meshes + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + aiMesh *mesh = in[node->mMeshes[i]]; - // check whether we can operate on this mesh - if (!mesh->mBones || *reinterpret_cast(mesh->mBones) == node->mTransformation) { - // yes, we can. - mesh->mBones = reinterpret_cast (&node->mTransformation); - mesh->mNumBones = UINT_MAX; - } - else { + // check whether we can operate on this mesh + if (!mesh->mBones || *reinterpret_cast(mesh->mBones) == node->mTransformation) { + // yes, we can. + mesh->mBones = reinterpret_cast(&node->mTransformation); + mesh->mNumBones = UINT_MAX; + } else { - // try to find us in the list of newly created meshes - for (unsigned int n = 0; n < out.size(); ++n) { - aiMesh* ctz = out[n]; - if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { + // try to find us in the list of newly created meshes + for (unsigned int n = 0; n < out.size(); ++n) { + aiMesh *ctz = out[n]; + if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { - // ok, use this one. Update node mesh index - node->mMeshes[i] = numIn + n; - } - } - if (node->mMeshes[i] < numIn) { - // Worst case. Need to operate on a full copy of the mesh - ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); - aiMesh* ntz; + // ok, use this one. Update node mesh index + node->mMeshes[i] = numIn + n; + } + } + if (node->mMeshes[i] < numIn) { + // Worst case. Need to operate on a full copy of the mesh + ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); + aiMesh *ntz; - const unsigned int tmp = mesh->mNumBones; // - mesh->mNumBones = 0; - SceneCombiner::Copy(&ntz,mesh); - mesh->mNumBones = tmp; + const unsigned int tmp = mesh->mNumBones; // + mesh->mNumBones = 0; + SceneCombiner::Copy(&ntz, mesh); + mesh->mNumBones = tmp; - ntz->mNumBones = node->mMeshes[i]; - ntz->mBones = reinterpret_cast (&node->mTransformation); + ntz->mNumBones = node->mMeshes[i]; + ntz->mBones = reinterpret_cast(&node->mTransformation); - out.push_back(ntz); + out.push_back(ntz); - node->mMeshes[i] = static_cast(numIn + out.size() - 1); - } - } - } + node->mMeshes[i] = static_cast(numIn + out.size() - 1); + } + } + } - // call children - for (unsigned int i = 0; i < node->mNumChildren;++i) - BuildWCSMeshes(out,in,numIn,node->mChildren[i]); + // call children + for (unsigned int i = 0; i < node->mNumChildren; ++i) + BuildWCSMeshes(out, in, numIn, node->mChildren[i]); } // ------------------------------------------------------------------------------------------------ // Reset transformation matrices to identity -void PretransformVertices::MakeIdentityTransform(aiNode* nd) -{ - nd->mTransformation = aiMatrix4x4(); +void PretransformVertices::MakeIdentityTransform(aiNode *nd) const { + nd->mTransformation = aiMatrix4x4(); - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - MakeIdentityTransform(nd->mChildren[i]); + // call children + for (unsigned int i = 0; i < nd->mNumChildren; ++i) + MakeIdentityTransform(nd->mChildren[i]); } // ------------------------------------------------------------------------------------------------ // Build reference counters for all meshes -void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs) -{ - for (unsigned int i = 0; i< nd->mNumMeshes;++i) - refs[nd->mMeshes[i]]++; +void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const { + for (unsigned int i = 0; i < nd->mNumMeshes; ++i) + refs[nd->mMeshes[i]]++; - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - BuildMeshRefCountArray(nd->mChildren[i],refs); + // call children + for (unsigned int i = 0; i < nd->mNumChildren; ++i) + BuildMeshRefCountArray(nd->mChildren[i], refs); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void PretransformVertices::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin"); +void PretransformVertices::Execute(aiScene *pScene) { + ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin"); - // Return immediately if we have no meshes - if (!pScene->mNumMeshes) - return; + // Return immediately if we have no meshes + if (!pScene->mNumMeshes) + return; - const unsigned int iOldMeshes = pScene->mNumMeshes; - const unsigned int iOldAnimationChannels = pScene->mNumAnimations; - const unsigned int iOldNodes = CountNodes(pScene->mRootNode); + const unsigned int iOldMeshes = pScene->mNumMeshes; + const unsigned int iOldAnimationChannels = pScene->mNumAnimations; + const unsigned int iOldNodes = CountNodes(pScene->mRootNode); - if(configTransform) { - pScene->mRootNode->mTransformation = configTransformation; - } + if (configTransform) { + pScene->mRootNode->mTransformation = configTransformation; + } - // first compute absolute transformation matrices for all nodes - ComputeAbsoluteTransform(pScene->mRootNode); + // first compute absolute transformation matrices for all nodes + ComputeAbsoluteTransform(pScene->mRootNode); - // Delete aiMesh::mBones for all meshes. The bones are - // removed during this step and we need the pointer as - // temporary storage - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - aiMesh* mesh = pScene->mMeshes[i]; + // Delete aiMesh::mBones for all meshes. The bones are + // removed during this step and we need the pointer as + // temporary storage + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + aiMesh *mesh = pScene->mMeshes[i]; - for (unsigned int a = 0; a < mesh->mNumBones;++a) - delete mesh->mBones[a]; + for (unsigned int a = 0; a < mesh->mNumBones; ++a) + delete mesh->mBones[a]; - delete[] mesh->mBones; - mesh->mBones = NULL; - } + delete[] mesh->mBones; + mesh->mBones = NULL; + } - // now build a list of output meshes - std::vector apcOutMeshes; + // now build a list of output meshes + std::vector apcOutMeshes; - // Keep scene hierarchy? It's an easy job in this case ... - // we go on and transform all meshes, if one is referenced by nodes - // with different absolute transformations a depth copy of the mesh - // is required. - if( configKeepHierarchy ) { + // Keep scene hierarchy? It's an easy job in this case ... + // we go on and transform all meshes, if one is referenced by nodes + // with different absolute transformations a depth copy of the mesh + // is required. + if (configKeepHierarchy) { - // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones - BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode); + // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones + BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode); - // ... if new meshes have been generated, append them to the end of the scene - if (apcOutMeshes.size() > 0) { - aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()]; + // ... if new meshes have been generated, append them to the end of the scene + if (apcOutMeshes.size() > 0) { + aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()]; - memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes); - memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size()); + memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes); + memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size()); - pScene->mNumMeshes += static_cast(apcOutMeshes.size()); - delete[] pScene->mMeshes; pScene->mMeshes = npp; - } + pScene->mNumMeshes += static_cast(apcOutMeshes.size()); + delete[] pScene->mMeshes; + pScene->mMeshes = npp; + } - // now iterate through all meshes and transform them to worldspace - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - ApplyTransform(pScene->mMeshes[i],*reinterpret_cast( pScene->mMeshes[i]->mBones )); + // now iterate through all meshes and transform them to worldspace + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + ApplyTransform(pScene->mMeshes[i], *reinterpret_cast(pScene->mMeshes[i]->mBones)); - // prevent improper destruction - pScene->mMeshes[i]->mBones = NULL; - pScene->mMeshes[i]->mNumBones = 0; - } - } else { - apcOutMeshes.reserve(pScene->mNumMaterials<<1u); - std::list aiVFormats; + // prevent improper destruction + pScene->mMeshes[i]->mBones = NULL; + pScene->mMeshes[i]->mNumBones = 0; + } + } else { + apcOutMeshes.reserve(pScene->mNumMaterials << 1u); + std::list aiVFormats; - std::vector s(pScene->mNumMeshes,0); - BuildMeshRefCountArray(pScene->mRootNode,&s[0]); + std::vector s(pScene->mNumMeshes, 0); + BuildMeshRefCountArray(pScene->mRootNode, &s[0]); - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - // get the list of all vertex formats for this material - aiVFormats.clear(); - GetVFormatList(pScene,i,aiVFormats); - aiVFormats.sort(); - aiVFormats.unique(); - for (std::list::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) { - unsigned int iVertices = 0; - unsigned int iFaces = 0; - CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices); - if (0 != iFaces && 0 != iVertices) - { - apcOutMeshes.push_back(new aiMesh()); - aiMesh* pcMesh = apcOutMeshes.back(); - pcMesh->mNumFaces = iFaces; - pcMesh->mNumVertices = iVertices; - pcMesh->mFaces = new aiFace[iFaces]; - pcMesh->mVertices = new aiVector3D[iVertices]; - pcMesh->mMaterialIndex = i; - if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices]; - if ((*j) & 0x4) - { - pcMesh->mTangents = new aiVector3D[iVertices]; - pcMesh->mBitangents = new aiVector3D[iVertices]; - } - iFaces = 0; - while ((*j) & (0x100 << iFaces)) - { - pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; - if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; - else pcMesh->mNumUVComponents[iFaces] = 2; - iFaces++; - } - iFaces = 0; - while ((*j) & (0x1000000 << iFaces)) - pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; + for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { + // get the list of all vertex formats for this material + aiVFormats.clear(); + GetVFormatList(pScene, i, aiVFormats); + aiVFormats.sort(); + aiVFormats.unique(); + for (std::list::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) { + unsigned int iVertices = 0; + unsigned int iFaces = 0; + CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices); + if (0 != iFaces && 0 != iVertices) { + apcOutMeshes.push_back(new aiMesh()); + aiMesh *pcMesh = apcOutMeshes.back(); + pcMesh->mNumFaces = iFaces; + pcMesh->mNumVertices = iVertices; + pcMesh->mFaces = new aiFace[iFaces]; + pcMesh->mVertices = new aiVector3D[iVertices]; + pcMesh->mMaterialIndex = i; + if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices]; + if ((*j) & 0x4) { + pcMesh->mTangents = new aiVector3D[iVertices]; + pcMesh->mBitangents = new aiVector3D[iVertices]; + } + iFaces = 0; + while ((*j) & (0x100 << iFaces)) { + pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; + if ((*j) & (0x10000 << iFaces)) + pcMesh->mNumUVComponents[iFaces] = 3; + else + pcMesh->mNumUVComponents[iFaces] = 2; + iFaces++; + } + iFaces = 0; + while ((*j) & (0x1000000 << iFaces)) + pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; - // fill the mesh ... - unsigned int aiTemp[2] = {0,0}; - CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]); - } - } - } + // fill the mesh ... + unsigned int aiTemp[2] = { 0, 0 }; + CollectData(pScene, pScene->mRootNode, i, *j, pcMesh, aiTemp, &s[0]); + } + } + } - // If no meshes are referenced in the node graph it is possible that we get no output meshes. - if (apcOutMeshes.empty()) { - - throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); - } - else - { - // now delete all meshes in the scene and build a new mesh list - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - aiMesh* mesh = pScene->mMeshes[i]; - mesh->mNumBones = 0; - mesh->mBones = NULL; + // If no meshes are referenced in the node graph it is possible that we get no output meshes. + if (apcOutMeshes.empty()) { - // we're reusing the face index arrays. avoid destruction - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { - mesh->mFaces[a].mNumIndices = 0; - mesh->mFaces[a].mIndices = NULL; - } + throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); + } else { + // now delete all meshes in the scene and build a new mesh list + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + aiMesh *mesh = pScene->mMeshes[i]; + mesh->mNumBones = 0; + mesh->mBones = NULL; - delete mesh; + // we're reusing the face index arrays. avoid destruction + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { + mesh->mFaces[a].mNumIndices = 0; + mesh->mFaces[a].mIndices = NULL; + } - // Invalidate the contents of the old mesh array. We will most - // likely have less output meshes now, so the last entries of - // the mesh array are not overridden. We set them to NULL to - // make sure the developer gets notified when his application - // attempts to access these fields ... - mesh = NULL; - } + delete mesh; - // It is impossible that we have more output meshes than - // input meshes, so we can easily reuse the old mesh array - pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - pScene->mMeshes[i] = apcOutMeshes[i]; - } - } - } + // Invalidate the contents of the old mesh array. We will most + // likely have less output meshes now, so the last entries of + // the mesh array are not overridden. We set them to NULL to + // make sure the developer gets notified when his application + // attempts to access these fields ... + mesh = NULL; + } - // remove all animations from the scene - for (unsigned int i = 0; i < pScene->mNumAnimations;++i) - delete pScene->mAnimations[i]; - delete[] pScene->mAnimations; + // It is impossible that we have more output meshes than + // input meshes, so we can easily reuse the old mesh array + pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + pScene->mMeshes[i] = apcOutMeshes[i]; + } + } + } - pScene->mAnimations = NULL; - pScene->mNumAnimations = 0; + // remove all animations from the scene + for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) + delete pScene->mAnimations[i]; + delete[] pScene->mAnimations; - // --- we need to keep all cameras and lights - for (unsigned int i = 0; i < pScene->mNumCameras;++i) - { - aiCamera* cam = pScene->mCameras[i]; - const aiNode* nd = pScene->mRootNode->FindNode(cam->mName); - ai_assert(NULL != nd); + pScene->mAnimations = NULL; + pScene->mNumAnimations = 0; - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - cam->mPosition = nd->mTransformation * cam->mPosition; - cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt; - cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp; - } + // --- we need to keep all cameras and lights + for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { + aiCamera *cam = pScene->mCameras[i]; + const aiNode *nd = pScene->mRootNode->FindNode(cam->mName); + ai_assert(NULL != nd); - for (unsigned int i = 0; i < pScene->mNumLights;++i) - { - aiLight* l = pScene->mLights[i]; - const aiNode* nd = pScene->mRootNode->FindNode(l->mName); - ai_assert(NULL != nd); + // multiply all properties of the camera with the absolute + // transformation of the corresponding node + cam->mPosition = nd->mTransformation * cam->mPosition; + cam->mLookAt = aiMatrix3x3(nd->mTransformation) * cam->mLookAt; + cam->mUp = aiMatrix3x3(nd->mTransformation) * cam->mUp; + } - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - l->mPosition = nd->mTransformation * l->mPosition; - l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection; - l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp; - } + for (unsigned int i = 0; i < pScene->mNumLights; ++i) { + aiLight *l = pScene->mLights[i]; + const aiNode *nd = pScene->mRootNode->FindNode(l->mName); + ai_assert(NULL != nd); - if( !configKeepHierarchy ) { + // multiply all properties of the camera with the absolute + // transformation of the corresponding node + l->mPosition = nd->mTransformation * l->mPosition; + l->mDirection = aiMatrix3x3(nd->mTransformation) * l->mDirection; + l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp; + } - // now delete all nodes in the scene and build a new - // flat node graph with a root node and some level 1 children - aiNode* newRoot = new aiNode(); - newRoot->mName = pScene->mRootNode->mName; - delete pScene->mRootNode; - pScene->mRootNode = newRoot; + if (!configKeepHierarchy) { - if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) - { - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; - } - else - { - pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras; - aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; + // now delete all nodes in the scene and build a new + // flat node graph with a root node and some level 1 children + aiNode *newRoot = new aiNode(); + newRoot->mName = pScene->mRootNode->mName; + delete pScene->mRootNode; + pScene->mRootNode = newRoot; - // generate mesh nodes - for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName = pScene->mMeshes[i]->mName; + if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) { + pScene->mRootNode->mNumMeshes = 1; + pScene->mRootNode->mMeshes = new unsigned int[1]; + pScene->mRootNode->mMeshes[0] = 0; + } else { + pScene->mRootNode->mNumChildren = pScene->mNumMeshes + pScene->mNumLights + pScene->mNumCameras; + aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; - // setup mesh indices - pcNode->mNumMeshes = 1; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - } - // generate light nodes - for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i); - pScene->mLights[i]->mName = pcNode->mName; - } - // generate camera nodes - for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i); - pScene->mCameras[i]->mName = pcNode->mName; - } - } - } - else { - // ... and finally set the transformation matrix of all nodes to identity - MakeIdentityTransform(pScene->mRootNode); - } + // generate mesh nodes + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++nodes) { + aiNode *pcNode = new aiNode(); + *nodes = pcNode; + pcNode->mParent = pScene->mRootNode; + pcNode->mName = pScene->mMeshes[i]->mName; - if (configNormalize) { - // compute the boundary of all meshes - aiVector3D min,max; - MinMaxChooser ()(min,max); + // setup mesh indices + pcNode->mNumMeshes = 1; + pcNode->mMeshes = new unsigned int[1]; + pcNode->mMeshes[0] = i; + } + // generate light nodes + for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++nodes) { + aiNode *pcNode = new aiNode(); + *nodes = pcNode; + pcNode->mParent = pScene->mRootNode; + pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u", i); + pScene->mLights[i]->mName = pcNode->mName; + } + // generate camera nodes + for (unsigned int i = 0; i < pScene->mNumCameras; ++i, ++nodes) { + aiNode *pcNode = new aiNode(); + *nodes = pcNode; + pcNode->mParent = pScene->mRootNode; + pcNode->mName.length = ::ai_snprintf(pcNode->mName.data, MAXLEN, "cam_%u", i); + pScene->mCameras[i]->mName = pcNode->mName; + } + } + } else { + // ... and finally set the transformation matrix of all nodes to identity + MakeIdentityTransform(pScene->mRootNode); + } - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - min = std::min(m->mVertices[i],min); - max = std::max(m->mVertices[i],max); - } - } + if (configNormalize) { + // compute the boundary of all meshes + aiVector3D min, max; + MinMaxChooser()(min, max); - // find the dominant axis - aiVector3D d = max-min; - const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5); + for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { + aiMesh *m = pScene->mMeshes[a]; + for (unsigned int i = 0; i < m->mNumVertices; ++i) { + min = std::min(m->mVertices[i], min); + max = std::max(m->mVertices[i], max); + } + } - d = min + d * (ai_real)0.5; - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - m->mVertices[i] = (m->mVertices[i]-d)/div; - } - } - } + // find the dominant axis + aiVector3D d = max - min; + const ai_real div = std::max(d.x, std::max(d.y, d.z)) * ai_real(0.5); - // print statistics - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); + d = min + d * (ai_real)0.5; + for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { + aiMesh *m = pScene->mMeshes[a]; + for (unsigned int i = 0; i < m->mNumVertices; ++i) { + m->mVertices[i] = (m->mVertices[i] - d) / div; + } + } + } - ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", - CountNodes(pScene->mRootNode) ," output nodes)" ); - ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras." ); - ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); - } + // print statistics + if (!DefaultLogger::isNullLogger()) { + ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); + + ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", + CountNodes(pScene->mRootNode), " output nodes)"); + ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras."); + ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); + } } diff --git a/code/PostProcessing/PretransformVertices.h b/code/PostProcessing/PretransformVertices.h index b2982951e..7898f6ae3 100644 --- a/code/PostProcessing/PretransformVertices.h +++ b/code/PostProcessing/PretransformVertices.h @@ -59,7 +59,7 @@ struct aiNode; class PretransformVerticesTest; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** The PretransformVertices pre-transforms all vertices in the node tree @@ -68,97 +68,97 @@ namespace Assimp { */ class ASSIMP_API PretransformVertices : public BaseProcess { public: - PretransformVertices (); - ~PretransformVertices (); + PretransformVertices(); + ~PretransformVertices(); - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; + // ------------------------------------------------------------------- + // Check whether step is active + bool IsActive(unsigned int pFlags) const override; - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); + // ------------------------------------------------------------------- + // Execute step on a given scene + void Execute(aiScene *pScene) override; - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); + // ------------------------------------------------------------------- + // Setup import settings + void SetupProperties(const Importer *pImp) override; - // ------------------------------------------------------------------- - /** @brief Toggle the 'keep hierarchy' option + // ------------------------------------------------------------------- + /** @brief Toggle the 'keep hierarchy' option * @param keep true for keep configuration. */ - void KeepHierarchy(bool keep) { - configKeepHierarchy = keep; - } + void KeepHierarchy(bool keep) { + configKeepHierarchy = keep; + } - // ------------------------------------------------------------------- - /** @brief Check whether 'keep hierarchy' is currently enabled. + // ------------------------------------------------------------------- + /** @brief Check whether 'keep hierarchy' is currently enabled. * @return ... */ - bool IsHierarchyKept() const { - return configKeepHierarchy; - } + bool IsHierarchyKept() const { + return configKeepHierarchy; + } private: - // ------------------------------------------------------------------- - // Count the number of nodes - unsigned int CountNodes( aiNode* pcNode ); + // ------------------------------------------------------------------- + // Count the number of nodes + unsigned int CountNodes(const aiNode *pcNode) const; - // ------------------------------------------------------------------- - // Get a bitwise combination identifying the vertex format of a mesh - unsigned int GetMeshVFormat(aiMesh* pcMesh); + // ------------------------------------------------------------------- + // Get a bitwise combination identifying the vertex format of a mesh + unsigned int GetMeshVFormat(aiMesh *pcMesh) const; - // ------------------------------------------------------------------- - // Count the number of vertices in the whole scene and a given - // material index - void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - unsigned int* piFaces, - unsigned int* piVertices); + // ------------------------------------------------------------------- + // Count the number of vertices in the whole scene and a given + // material index + void CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, + unsigned int iMat, + unsigned int iVFormat, + unsigned int *piFaces, + unsigned int *piVertices) const; - // ------------------------------------------------------------------- - // Collect vertex/face data - void CollectData( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - aiMesh* pcMeshOut, - unsigned int aiCurrent[2], - unsigned int* num_refs); + // ------------------------------------------------------------------- + // Collect vertex/face data + void CollectData(const aiScene *pcScene, const aiNode *pcNode, + unsigned int iMat, + unsigned int iVFormat, + aiMesh *pcMeshOut, + unsigned int aiCurrent[2], + unsigned int *num_refs) const; - // ------------------------------------------------------------------- - // Get a list of all vertex formats that occur for a given material - // The output list contains duplicate elements - void GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list& aiOut); + // ------------------------------------------------------------------- + // Get a list of all vertex formats that occur for a given material + // The output list contains duplicate elements + void GetVFormatList(const aiScene *pcScene, unsigned int iMat, + std::list &aiOut) const; - // ------------------------------------------------------------------- - // Compute the absolute transformation matrices of each node - void ComputeAbsoluteTransform( aiNode* pcNode ); + // ------------------------------------------------------------------- + // Compute the absolute transformation matrices of each node + void ComputeAbsoluteTransform(aiNode *pcNode); - // ------------------------------------------------------------------- - // Simple routine to build meshes in worldspace, no further optimization - void BuildWCSMeshes(std::vector& out, aiMesh** in, - unsigned int numIn, aiNode* node); + // ------------------------------------------------------------------- + // Simple routine to build meshes in worldspace, no further optimization + void BuildWCSMeshes(std::vector &out, aiMesh **in, + unsigned int numIn, aiNode *node) const; - // ------------------------------------------------------------------- - // Apply the node transformation to a mesh - void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat); + // ------------------------------------------------------------------- + // Apply the node transformation to a mesh + void ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const; - // ------------------------------------------------------------------- - // Reset transformation matrices to identity - void MakeIdentityTransform(aiNode* nd); + // ------------------------------------------------------------------- + // Reset transformation matrices to identity + void MakeIdentityTransform(aiNode *nd) const; - // ------------------------------------------------------------------- - // Build reference counters for all meshes - void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); + // ------------------------------------------------------------------- + // Build reference counters for all meshes + void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const; - //! Configuration option: keep scene hierarchy as long as possible - bool configKeepHierarchy; - bool configNormalize; - bool configTransform; - aiMatrix4x4 configTransformation; - bool mConfigPointCloud; + //! Configuration option: keep scene hierarchy as long as possible + bool configKeepHierarchy; + bool configNormalize; + bool configTransform; + aiMatrix4x4 configTransformation; + bool mConfigPointCloud; }; } // end of namespace Assimp diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index 4e3f111da..d607d27a5 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -202,6 +202,7 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset } mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); + mat->AddProperty(&prop.texCoord, 1, AI_MATKEY_GLTF_TEXTURE_TEXCOORD(texType, texSlot)); if (prop.textureTransformSupported) { aiUVTransform transform; diff --git a/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.bin b/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.bin new file mode 100644 index 000000000..ae6a3f0d1 Binary files /dev/null and b/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.bin differ diff --git a/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf b/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf new file mode 100644 index 000000000..382127a3a --- /dev/null +++ b/test/models/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf @@ -0,0 +1,172 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v1.0.5", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0, + 1, + 2 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube" + }, + { + "name" : "Light", + "rotation" : [ + 0.16907575726509094, + 0.7558803558349609, + -0.27217137813568115, + 0.570947527885437 + ], + "translation" : [ + 4.076245307922363, + 5.903861999511719, + -1.0054539442062378 + ] + }, + { + "name" : "Camera", + "rotation" : [ + 0.483536034822464, + 0.33687159419059753, + -0.20870360732078552, + 0.7804827094078064 + ], + "translation" : [ + 7.358891487121582, + 4.958309173583984, + 6.925790786743164 + ] + } + ], + "materials" : [ + { + "doubleSided" : true, + "name" : "Material", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0, + "texCoord" : 0 + }, + "metallicFactor" : 0, + "metallicRoughnessTexture" : { + "index" : 0, + "texCoord" : 1 + } + } + } + ], + "meshes" : [ + { + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1, + "TEXCOORD_0" : 2, + "TEXCOORD_1" : 3 + }, + "indices" : 4, + "material" : 0 + } + ] + } + ], + "textures" : [ + { + "source" : 0 + } + ], + "images" : [ + { + "mimeType" : "image/png", + "name" : "Material Base Color", + "uri" : "texture.png" + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 24, + "max" : [ + 1, + 1, + 1 + ], + "min" : [ + -1, + -1, + -1 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 24, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 24, + "type" : "VEC2" + }, + { + "bufferView" : 3, + "componentType" : 5126, + "count" : 24, + "type" : "VEC2" + }, + { + "bufferView" : 4, + "componentType" : 5123, + "count" : 36, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 288 + }, + { + "buffer" : 0, + "byteLength" : 192, + "byteOffset" : 576 + }, + { + "buffer" : 0, + "byteLength" : 192, + "byteOffset" : 768 + }, + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 960 + } + ], + "buffers" : [ + { + "byteLength" : 1032, + "uri" : "boxTexcoords.bin" + } + ] +} diff --git a/test/models/glTF2/BoxTexcoords-glTF/texture.png b/test/models/glTF2/BoxTexcoords-glTF/texture.png new file mode 100644 index 000000000..2350eb845 Binary files /dev/null and b/test/models/glTF2/BoxTexcoords-glTF/texture.png differ diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 6443d740f..2073a0003 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include + using namespace Assimp; class utglTF2ImportExport : public AbstractImportExportBase { @@ -464,3 +466,30 @@ TEST_F(utglTF2ImportExport, sceneMetadata) { ASSERT_EQ(strcmp(generator.C_Str(), "COLLADA2GLTF"), 0); } } + +TEST_F(utglTF2ImportExport, texcoords) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf", + aiProcess_ValidateDataStructure); + ASSERT_NE(scene, nullptr); + + ASSERT_TRUE(scene->HasMaterials()); + const aiMaterial *material = scene->mMaterials[0]; + + aiString path; + aiTextureMapMode modes[2]; + EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, + nullptr, nullptr, modes)); + EXPECT_STREQ(path.C_Str(), "texture.png"); + + int uvIndex = -1; + EXPECT_EQ(aiGetMaterialInteger(material, AI_MATKEY_GLTF_TEXTURE_TEXCOORD(aiTextureType_DIFFUSE, 0), &uvIndex), aiReturn_SUCCESS); + EXPECT_EQ(uvIndex, 0); + + // Using manual macro expansion of AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE here. + // The following works with some but not all compilers: + // #define APPLY(X, Y) X(Y) + // ..., APPLY(AI_MATKEY_GLTF_TEXTURE_TEXCOORD, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE), ... + EXPECT_EQ(aiGetMaterialInteger(material, AI_MATKEY_GLTF_TEXTURE_TEXCOORD(aiTextureType_UNKNOWN, 0), &uvIndex), aiReturn_SUCCESS); + EXPECT_EQ(uvIndex, 1); +}